Group SQL query results by year - php

I'm new in SQL and I need to group the results of a query by year.
In other words, I have this table structure:
id | title | date
My current query SELECT * FROM table
My current result:
array =>
0 =>
array =>
...
'date' => string '2018-03-09'
1 =>
array =>
...
'date' => string '2018-03-15'
2 =>
array =>
...
'date' => string '2017-03-15'
And I need something like that:
array =>
0 =>
array =>
...
'date' => string '2018-03-09'
array =>
...
'date' => string '2018-03-15'
1 =>
array =>
...
'date' => string '2017-03-15'
Thanks in advance for help :)
[EDIT]
I finally found a way to do what I wanted:
$result = $sql->query("SELECT * FROM abstract ORDER BY date DESC");
$array = [];
forEach($result as $res) {
$year = strtok($res['date'], '-');
if (!isset($array[$year]))
$array[$year][0] = $res;
else
array_push($array[$year], $res);
}
return $array;

If you want group data by year.
Select id,title,date,DATE_FORMAT(date, '%Y') YEAR_GRP from table group by YEAR_GRP

This is something you'll want to do in your query, as MySQL can do it much more efficiently, than PHP.
The way to do it is to add a GROUP BY clause to your query, which will batch rows in your resultset into a single row, based on a grouping value, which in your case will be YEAR(date), as you're looking to group items by the year component in each line's date.
Because you're still looking to have all the results returned, merely grouped by each distinct grouping value, you'll need to use an Aggregate Function to combine all the matching lines into an array of values. Luckily MySQL has a function called json_objectagg which does exactly what you need.
So you'll end up with a query that looks something like:
SELECT year(`date`) AS `year`, json_objectagg(id, `date`, title) AS `line`
FROM abstract
GROUP BY `year`
Instead of json_objectagg, alternatives are e.g. json_arrayagg
SELECT year(`date`) AS `year`, json_arrayagg(id, `date`, title) AS `line`
...or group_concat
SELECT year(`date`) AS `year`, group_concat(id, `date`, title) AS `line`
...depending on what kind of output you require.

Related

Php mysql join to subarray with field names

I trying to join table using ONE query into sub array with column name => column value..
Short table(1) "users" structure with data:
user_id email ...
1 xxx#xx.xx ...
2 yyy#yy.yy ...
Short table(2) "users_permissions" structure with data:
user_id plugin_enter offers_view ...
1 1 0 ...
2 1 1 ...
If i use classic method - join left
SELECT `uperms`.*, `u`.*
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
I get classic output
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'plugin_enter' => 1,
'offers_view' => 0
),
[1] = array(
'user_id' => 2,
'email' => yyy#yy.yy,
'plugin_enter' => 1,
'offers_view' => 1,
...
),
All i need is output into subarray as this:
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'permissions => array(
'plugin_enter' => 1,
'offers_view' => 0
),
),
...
Is this possible to do with ONE query?
Table2 (permissions) contains about 60 columns. Is possible to CONCAT column's names with column value, if is joined to Table1 only one row?
MySQL doesn't have arrays or nested structures, so it's not possible to do this in SQL.
Change your query so you give all the fields from users_permissions a consistent naming style. Then you can use a PHP loop to collect all the array elements whose keys match that pattern into the permissions array.
Query:
SELECT u.*, up.plugin_enter AS perm_plugin_enter, up.offers_view AS perm_offers_view, ...
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
PHP:
foreach ($all_results as &$row) {
$permissions = array();
foreach ($row as $key => $value) {
if (strpos($key, 'perm_') === 0) {
$permission[substr($key, 5)] = $value;
unset($row[$key]);
}
}
$row['permissions'] = $permissions;
}
You could do it by concatenating all the column names and values in the table:
SELECT u.*, CONCAT_WS(',', CONCAT('plugin_enter:', plugin_enter), CONCAT('offers_view:', offers_view), ...) AS permissions
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
Then your PHP code can use explode() to split $row['permissions'] into array of name:value pairs, and then convert those to key=>value in the PHP array.
Another solution is to redesign your users_permissions table:
user_id permission_type value
1 plugin_enter 1
1 offers_view 0
...
2 plugin_enter 1
2 offers_view 1
...
Then you can query:
SELECT u.*, GROUP_CONCAT(permission_type, ':', value) AS permission
FROM users AS u
JOIN users_permissions AS up on u.user_id = up.user_id
Another possible sollution is to add prefixes to query.
Inspired by post: https://stackoverflow.com/a/9926134/2795923
SELECT `u`.*, ':prefix_start:', `uperms`.*, ':prefix_end:'
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
Output array looks like this:
[0] => array(
'user_id' => 1
'email' => xxx#xx.xx,
'prefix_start' =>
'plugin_enter' => 1,
'offers_view' => 0
'prefix_end' =>
)
...
Then easy PHP script to add all array data between prefix_start and prefix_end into own subarray.

How to take Count (*) as variable from SQL to php?

I have made request to SQL:
SELECT meta_value, COUNT(*) from wp_postmeta;
and have in respond an array:
array (size=102)
0 =>
object(stdClass)[24]
public 'meta_value' => string '37' (length=2)
public 'COUNT(*)' => string '147' (length=3)
1 =>
object(stdClass)[23]
public 'meta_value' => string '32' (length=2)
public 'COUNT(*)' => string '143' (length=3)
I take "meta_value" without any troubles with php code:
$result->meta_value;
But how take values of public 'COUNT(*)' => string '143' (length=3)?
I have tried different syntaxis and some errors only.
I need values: 147,143...
Use AS to create an alias
SELECT meta_value, COUNT(*) As count from wp_postmeta;
then use count
Use the alias AS in your SQL to give the MySQL function a desired name.
SELECT meta_value, COUNT(*) as counter from wp_postmeta;
SELECT meta_value, COUNT(*) AS total from wp_postmeta;
This is good solution.
But you can do it alternative way(if you want to keep your query as it is)
$total="count(*)";//keep it inside a variable;
//now you can use it
$result->$total;
$result->count(*) will produce syntax error but $result->$total; will work
You can use a alias name with AS like this:
SELECT meta_value, COUNT(*) as xy from wp_postmeta;
SELECT meta_value,COUNT(*) AS total_count FROM wp_postmeta
echo $result->total_count;

Counting occurrences of a field based on another field

I'm trying to count a certain field and how much it occurs based on a date. For example, I have a reputation field that I need counted, so if there is 5 reputation points that were individually submitted on 12/14/2014, how would I get the total amount and not just 5 rows?
This is an example of what I am trying to do (if it helps explain it better)
'ID' => 1,
'rep' => 'SK01',
'25/11/14' => '5',
'26/11/14' => '23',
'27/11/14' => '3',
'28/11/14' => '87',
'29/11/14' => '4',
'01/12/14' => '45',
'02/12/14' => '145',
On today [ 2014-12-08 09:53:27 ] there were 1 for AH05 (I'm just getting a repeat of that however many times it is in table) Here is the SQL also if that helps
SELECT *, COUNT(*) as TotalValueCount, DATE(date_created) AS thedate
FROM wp_rg_lead INNER JOIN wp_rg_lead_detail ON wp_rg_lead.id = wp_rg_lead_detail.lead_id
WHERE wp_rg_lead.form_id = '47' AND date_created BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY)
AND NOW() AND field_number = '18' GROUP BY value, date_created
You would do a group by query, but the results would be in rows, not columns:
select rep, date, count(*)
from table t
group by rep, date;
If, for some reason, you really have to have the values in columns, I would suggest doing it at the application layer. Otherwise, Google "MySQL dynamic pivot" to get ideas on what to do.

Desirable result in "UNION"

MY sql query is
SELECT id, content FROM table1
UNION ALL
SELECT p_id, p_content FROM table2;
It is giving the desirable result but with column name of first select statement.
e.g
if the query get the data from second select statement it give the result as
array (size=2)
'id' => string '15' (length=2)
'content' => string 'table2 content' (length=22)
i want column name with respective select statement result.
e.g
if select got result from first select then the array of result should be like this
array (size=2)
'id' => string '15' (length=2)
'content' => string 'table1 content' (length=22)
else if select got result from second select statement then the array of result should be like this
array (size=2)
'**p_id**' => string '15' (length=2)
'**p_content**' => string 'table2 content' (length=22)
This is not possible. The column names will be the same throughout the query result. Those column names are actually the column names of the query result and don't need to be the same as column names in the table(s):
SELECT id as Numbers, content as Texts FROM table1
UNION ALL
SELECT p_id, p_content FROM table2;
You can execute two separate queries and process their results separately.
Or otherwise you could return an extra constant value to determine between the results:
SELECT id, content, '1' as TableNr FROM table1
UNION ALL
SELECT p_id, p_content, '2' FROM table2;
Now, for each row you can ask the value of the column 'TableNr' to see which table it came from.

Issue with UNION Query

I'm trying what seems to be a simple union query for two tables in my database though I am unable to retrieve a successful array result. It should be noted that each table has different columns and that I'd like to create a virtual result (promo AS origin [for the result pulled from the 'venpromo' table] && vacation AS origin [for the result pulled from the 'vacation' table]) in order to sort the results into different array structures. I've looked everywhere and UNIONS are all using different syntax. Thank you all in advance!
<?php
require_once('includes/config.php');
$event_query = "SELECT *, promo AS origin FROM venpromo
UNION
SELECT *, vacation AS origin FROM venpromo
ORDER BY popularity DESC";
$event_result = mysql_query($event_query, $connection);
while ($event = mysql_fetch_array($event_result)) {
if ($event['origin'] == "promo") {
$event_array[] = array(
'id' => $event['id'],
'title' => $event['calname'],
'start' => $event['sdate'],
'end' => $event['edate'],
'color' => "red",
'url' => "http://www.norrisportal.com/bulletinpost.php?id=" . $event['id'] . "&hashkey=akdULjsjyUpYyTzOT7"
);
} elseif ($event['origin'] == "vacation") {
$event_array[] = array(
'id' => $event['id'],
'title' => $event['reason'],
'start' => $event['vacstart'],
'end' => $event['vacend'],
'color' => "blue"
);
}
}
echo json_encode($event_array);
?>
When visiting the page to view the results, I see 'null'.
Put the columns names explicitly rather than *, and make sure the number of columns and data types match for the same column in each select.
I have added some dummy columns to match the number and data types in both the tables and also changed the order of the columns.
try this sample way ::
select
id,
uid,
approval,
vacstart,
vacend,
reason,
'dummy1' col1,
'dummy2' col2,
'dummy3' col3,
curdate() col4,
'dummy4' col5,
'dummy5' col6,
'dummy6' col7,
'dummy7' col8,
promo AS origin
from vacation
union
select
id,
venid,
authid,
sdate,
edate,
authname,
tags,
title,
calname,
date,
intro,
body,
sum,
sortdate,
vacation AS origin
from venpromo;

Categories