sql query to set year as column name - mysql

By writing the following query
SELECT item_name, YEAR( DATE ) , SUM( item_sold_qty )
FROM item
JOIN sales ON item.id = sales.item_number
GROUP BY YEAR( DATE ) , item_name
ORDER BY item_name
i'm able to get the following result
item_name YEAR( DATE ) SUM( item_sold_qty )
pencil 2011 22
pencil 2012 44
eraser 2012 22
eraser 2011 11
pen 2012 66
pen 2011 33
nib 2012 88
nib 2011 44
Instead i want the result in the following way
item_name 2011 2012
pencil 22 44
eraser 11 22
pen 33 66
nib 44 88
I'm not really good at sql and have no clue for how to set the years as column names.
Need help.
NOTE :: My database has 2 tables. Sales table has date column which has different dates like 2012-03-01, 2012-04-02, 2011-07-03, so on...

Maybe something like this:
SELECT
item_name,
SUM(CASE WHEN YEAR( DATE )=2011 THEN item_sold_qty ELSE 0 END) AS '2011',
SUM(CASE WHEN YEAR( DATE )=2012 THEN item_sold_qty ELSE 0 END) AS '2012'
FROM
item
JOIN sales ON item.id = sales.item_number
GROUP BY
item_name
ORDER BY
item_name
EDIT
If you want the other years and still sum them. Then you can do this:
SELECT
item_name,
SUM(CASE WHEN YEAR( DATE )=2011 THEN item_sold_qty ELSE 0 END) AS '2011',
SUM(CASE WHEN YEAR( DATE )=2012 THEN item_sold_qty ELSE 0 END) AS '2012',
SUM(CASE WHEN NOT YEAR( DATE ) IN (2011,2012) THEN item_sold_qty ELSE 0 END) AS 'AllOtherYears'
FROM
item
JOIN sales ON item.id = sales.item_number
GROUP BY
item_name
ORDER BY
item_name
EDIT2
If you have a lot of years and you do not want to keep on adding years. Then you need to using dynamic sql. That means that you concat a varchar of the sql and then execute it.
Useful References:
MySQL pivot table with dynamic headers based on single column data
How To have Dynamic SQL in MySQL Stored Procedure
MySQL/Pivot table
MYSQL - Rows to Columns

The answer above will work but adding a case for ever year may or may not be suitable.
If you're on a PHP platform you could change the layout of your existing array like such
foreach($items as $item)
{
$item_names[$item[item_name]][$item[year]] += $item[item_sold_qty];
}
This will make an array as follows:
Array
(
[pencil] => Array
(
[2011] => 22
[2012] => 44
)
[eraser] => Array
(
[2012] => 22
[2011] => 11
)
[pen] => Array
(
[2012] => 66
[2011] => 33
)
[nib] => Array
(
[2012] => 88
[2011] => 44
)
)
Also change your original query to assign better names to the variables:
SELECT item_name, YEAR( DATE ) as year , SUM( item_sold_qty ) as item_sold_qty
FROM item
JOIN sales ON item.id = sales.item_number
GROUP BY YEAR( DATE ) , item_name
ORDER BY item_name
The above assumes your mysql result array looks something like this:
Array
(
[0] => Array
(
[item_name] => pencil
[year] => 2011
[item_sold_qty] => 22
)
[1] => Array
(
[item_name] => pencil
[year] => 2012
[item_sold_qty] => 44
)
[2] => Array
(
[item_name] => eraser
[year] => 2012
[item_sold_qty] => 22
)
[3] => Array
(
[item_name] => eraser
[year] => 2011
[item_sold_qty] => 11
)
[4] => Array
(
[item_name] => pen
[year] => 2012
[item_sold_qty] => 66
)
[5] => Array
(
[item_name] => pen
[year] => 2011
[item_sold_qty] => 33
)
[6] => Array
(
[item_name] => nib
[year] => 2012
[item_sold_qty] => 88
)
[7] => Array
(
[item_name] => nib
[year] => 2011
[item_sold_qty] => 44
)
)

Here:
SELECT
i.item_name,
SUM(s1.item_sold_qty) AS '2011',
SUM(s2.item_sold_qty) AS '2012'
FROM item i
LEFT JOIN sales s1 ON (i.id = s1.item_number AND YEAR(s1.DATE) = 2011)
LEFT JOIN sales s2 ON (i.id = s2.item_number AND YEAR(s2.DATE) = 2012)
GROUP BY i.item_name
ORDER BY i.item_name
Of course, you will have to add as many joins as many years you want to search through...

Related

Grouping MySQL results from query

I am trying to create a basic notification system. The function below works well, however I'd like to be able to group notifications for the same notification item into the same array item. So, any query result that has the same [item] and [item_id] would be grouped together and just update the count for that item group. So I guess adding a new array item count for that group? I have no idea how to approach this. Any help would be much appreciated.
Query Function:
function get_notifications($connect, $user_id) {
$query = "SELECT * FROM notifications WHERE for_id = {$user_id} AND seen = 0 ";
$result = mysqli_query($connect, $query) or die(mysql_error($connect));
while($row = mysqli_fetch_assoc($result)){
$notifs[] = $row;
}
return $notifs;
}
$notifs = get_notifications($connect, $_SESSION['user_id']);
Current Result:
Array
(
[0] => Array
(
[note_id] => 3
[for_id] => 20
[from_id] => 20
[item] => like_pp
[item_id] => 104
[seen] => 0
[date] => 2022-01-19 12:55:20
)
[1] => Array
(
[note_id] => 4
[for_id] => 20
[from_id] => 20
[item] => like_comment
[item_id] => 332
[seen] => 0
[date] => 0000-00-00 00:00:00
)
[2] => Array
(
[note_id] => 5
[for_id] => 20
[from_id] => 23
[item] => like_pp
[item_id] => 104
[seen] => 0
[date] => 0000-00-00 00:00:00
)
[3] => Array
(
[note_id] => 6
[for_id] => 20
[from_id] => 20
[item] => pp_like
[item_id] => 102
[seen] => 0
[date] => 2022-01-19 15:03:23
)
)
Desired Result: ([item] => like_pp and [item_id] => 104 were the same so combined and updated notification_count)
Array
(
[0] => Array
(
[note_id] => 3
[for_id] => 20
[from_id] => 20
[item] => like_pp
[item_id] => 104
[seen] => 0
[notification_count] => 2
[date] => 2022-01-19 12:55:20
)
[1] => Array
(
[note_id] => 4
[for_id] => 20
[from_id] => 20
[item] => like_comment
[item_id] => 332
[seen] => 0
[notification_count] => 1
[date] => 0000-00-00 00:00:00
)
[2] => Array
(
[note_id] => 6
[for_id] => 20
[from_id] => 20
[item] => pp_like
[item_id] => 102
[seen] => 0
[notification_count] => 1
[date] => 2022-01-19 15:03:23
)
)
I think what you need is a the query that groups by user_id (for who) and item_id (for what type of notif) and delivers the count of this group. Something like:
$query = "SELECT count(*) as notification_count, for_id, item_id FROM notifications WHERE for_id = {$user_id} AND seen = 0 group by for_id, item_id ";
Optionally, if you need in the output the name of the item, for displaying or other purposes, it can be also added:
$query = "SELECT count(*) as notification_count, for_id, item_id, item FROM notifications WHERE for_id = {$user_id} AND seen = 0 group by for_id, item_id, item ";
Use GROUP BY and aggregation functions.
SELECT MIN(note_id) AS note_id, MIN(for_id) AS for_id, MIN(from_id) AS from_id,
item, item_id, MIN(seen) AS seen, COUNT(*) AS notification_count, MIN(date) as date
FROM notifications
WHERE for_id = {$user_id} AND seen = 0
GROUP BY item, item_id

Get month wise count from Mysql database even if there are no results

I am creating graph for display month wise count from Mysql database.
Execute this following query:
$cash_query = $this->db->query("select COUNT(*) as count_monthwise, MONTH(FROM_UNIXTIME(dt_added)) as month from `order` where user_id='1' and status != '9' and payment_type = '1' GROUP BY month");
$cash_result = $cash_query->result();
Output:
Array
(
[0] => stdClass Object
(
[count_monthwise] => 1
[month] => 8
)
[1] => stdClass Object
(
[count_monthwise] => 2
[month] => 9
)
)
In above output, there are display "count_monthwise" means count and month "8" means "8th month - August".
But i want to display output with all months, if find count are 0 in any months, then display [count_monthwise] => 0.
I want to display Exact output like:
Array
(
[0] => stdClass Object
(
[count_monthwise] => 1
[month] => 1
)
[1] => stdClass Object
(
[count_monthwise] => 1
[month] => 2
)
.
.
.
.
.
.
.
[10] => stdClass Object
(
[count_monthwise] => 0
[month] => 11
)
[11] => stdClass Object
(
[count_monthwise] => 0
[month] => 12
)
)
I have used using foreach loop something like this, but this is not working.
Loop
foreach($cash_result as $cash => $cash_value){
for($i=0;$i<=11;$i++){
if($i == $cash){
}
}
}
That could be the one way around:
SELECT
COALESCE(yourQuery.count_monthwise,0) AS monthwise_count,
allMonths.month
(SELECT 1 AS month UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12 ) AS allMonths
LEFT JOIN
(
SELECT
COUNT(*) as count_monthwise,
MONTH(FROM_UNIXTIME(dt_added)) as month
from `order`
where user_id='1' and status != '9' and payment_type = '1'
GROUP BY month
) AS yourQuery
ON allMonths.month = yourQuery.month
use below way after getting the result from database don't do complex query just do some code twist
$cash_result = $cash_query->result_array(); // make it to array
$month = range(1,12); // month array
$new_array = array();
$counta = count($month);
for($i=0; $i<$counta ; $i++){
foreach($arr as $key=>$row){
if(($month[$i] == $row['month'])){
$new_array[$i] = $arr[$key];
break;
}else{
$new_array[$i] = array('count_monthwise' => 0,'month' => $month[$i]);
}
}
}
echo '<pre>'; print_r($new_array);

unread count and grouping

I have a very similar setup to this answer Is there a simpler way to achieve this style of user messaging?
However I'm having an issue with getting the total unread conversations and not unread messages.
SELECT p.conversation_id, COUNT(p.conversation_id) as unread
FROM participation AS p
INNER JOIN messages AS m
ON m.conversation_id = p.conversation_id AND m.seen = 0
WHERE p.uid1 = {$user->data['id']}
GROUP BY m.conversation_id`
I'm only selecting p.conversation_id for testing purposes, but the result I am getting is:
Array
(
[conversation_id] => 1
[unread] => 77
)
If I were to put the results in a PHP while loop I get
Array
(
[conversation_id] => 1
[unread] => 77
)
Array
(
[conversation_id] => 3
[unread] => 7
)
Array
(
[conversation_id] => 8
[unread] => 1
)
Array
(
[conversation_id] => 17
[unread] => 35
)
Array
(
[conversation_id] => 22
[unread] => 2
)
Array
(
[conversation_id] => 24
[unread] => 305
)
Array
(
[conversation_id] => 29
[unread] => 41
)
Array
(
[conversation_id] => 31
[unread] => 1
)
The result I am wanting is unread: 8
I think you just want conditional aggregation:
SELECT p.conversation_id,
SUM(m.seen = 0) as unseen,
SUM(m.seen <> 0) as seen
FROM participation AS p INNER JOIN
messages AS m
ON m.conversation_id = p.conversation_id AND m.seen = 0
WHERE p.uid1 = {$user->data['id']}
GROUP BY m.conversation_id
In addition, if you want the total over all conversations, leave out the group by.

ORDER BY not working with raw SQL Query in Symfony2, but works on MySQL database

I have a query that returns a list of dates I use for a drop down date picker, here is the SQL query.
SELECT `completion_date`
FROM `enviro_figures_upload`
GROUP BY YEAR( completion_date ) , MONTH( completion_date )
ORDER BY YEAR( completion_date ) ASC , MONTH( completion_date ) ASC
Through phpMyAdmin, the query returns the results I need in the order I need:
2014-01-01
2014-02-01
2014-11-01
2014-12-01
2015-01-01
2015-02-01
In my Symfony2 application, here is the code I use to get this data to my application:
$sql4 = "SELECT `completion_date` FROM `enviro_figures_upload` GROUP BY YEAR(completion_date), MONTH(completion_date) ORDER BY YEAR(completion_date) ASC, MONTH(completion_date) ASC;";
$activeDateSelect = $this->getDoctrine()->getManager()->getConnection()->prepare($sql4);
$activeDateSelect->execute();
$activeDate = $activeDateSelect->fetchAll();
However, the results aren't in the correct order at all. The results that are returned are like this:
2014-01-01
2015-01-01
2014-11-01
2014-12-01
2015-02-01
I can't understand why the results are being changed like this. What can I do?
EDIT
The field type where the date is VARCHAR not DATE. This is because the client I'm building this for can't change the format of the date in Excel which he uses to create the CSV. So the date is uploaded in the UK format, at which point I then reformat the date to the current one.
Here is a var_dump of the fetchAll():
Array
(
[0] => Array
(
[completion_date] =>
)
[1] => Array
(
[completion_date] => 2014-01-06
)
[2] => Array
(
[completion_date] => 2014-02-06
)
[3] => Array
(
[completion_date] => 2014-03-06
)
[4] => Array
(
[completion_date] => 2014-04-06
)
[5] => Array
(
[completion_date] => 2014-05-06
)
[6] => Array
(
[completion_date] => 2014-06-06
)
[7] => Array
(
[completion_date] => 2014-07-06
)
[8] => Array
(
[completion_date] => 2014-08-06
)
[9] => Array
(
[completion_date] => 2014-09-05
)
[10] => Array
(
[completion_date] => 2014-10-05
)
[11] => Array
(
[completion_date] => 2014-11-05
)
[12] => Array
(
[completion_date] => 2014-12-05
)
[13] => Array
(
[completion_date] => 2015-01-01
)
[14] => Array
(
[completion_date] => 2015-02-01
)
[15] => Array
(
[completion_date] => 2015-03-01
)
)
EDIT 2
I iterate the results through Twig like this:
{% for ad in actdate %}
<option value="{{ad.completion_date|date('Y-m')}}">{{ad.completion_date|date('F Y')}}</option>
{% endfor %}

MySQL Replace string SUM then total

Looking to get a total for each ID from the sum of the replacement fields.
SELECT
insurance_carrier as ID, SUM(REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')) AS es_reserve,
SUM(REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))AS structure_reserve,
SUM(es_reserve+structure_reserve) AS total
FROM job_tbl
WHERE
job_status NOT IN(2,4,6,7,9) AND
insurance_carrier !=0 AND
FROM_UNIXTIME(date_of_loss,'%m') = MONTH(NOW()) AND
FROM_UNIXTIME(date_of_loss,'%Y') = YEAR(NOW())
GROUP BY insurance_carrier
I get the results from es_reserve and structure_reserve but the total is 0.
BTW the fields contain items like $2,300- that's the reason for the replace
Any help would be appreciated!!!
EDIT: here is the results this produces
Array
(
[ID] => 14
[es_reserve] => 5000
[structure_reserve] => 35000
)
Array
(
[ID] => 15
[es_reserve] => 2500
[structure_reserve] => 2500
)
Array
(
[ID] => 41
[es_reserve] => 2500
[structure_reserve] => 2500
)
Array
(
[ID] => 44
[es_reserve] => 2500
[structure_reserve] =>
)
Here is what I would like it to produce
Array
(
[ID] => 14
[es_reserve] => 5000
[structure_reserve] => 35000
[total] => 40000
)
Array
(
[ID] => 15
[es_reserve] => 2500
[structure_reserve] => 2500
[total] => 5000
)
Array
(
[ID] => 41
[es_reserve] => 2500
[structure_reserve] => 2500
[total] => 5000
)
Array
(
[ID] => 44
[es_reserve] => 2500
[structure_reserve] =>
[total] => 2500
)
Total column is doing sum on original column value , the alias name defined in the select won't be used in the same select.
You can repeat replace statement while doing total column computation
SUM( REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')
+ REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))
Total,
instead of
SUM(es_reserve+structure_reserve) as total
The query becomes, with order by as asked in comment.
SELECT insurance_carrier as ID, SUM(REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')) AS es_reserve, SUM(REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))AS structure_reserve, SUM( REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','') + REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-','')) as Total FROM job_tbl WHERE job_status NOT IN(2,4,6,7,9) AND insurance_carrier !=0 AND FROM_UNIXTIME(date_of_loss,'%m') = MONTH(NOW()) AND FROM_UNIXTIME(date_of_loss,'%Y') = YEAR(NOW()) GROUP BY insurance_carrier
order by SUM( REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','') + REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-','')) desc
OR
use it as subquery
SELECT T.*, SUM(es_reserve+structure_reserve) AS total
FROM
(
SELECT
insurance_carrier as ID, SUM(REPLACE(REPLACE(REPLACE(es_reserve,'$',''),',',''),'-','')) AS es_reserve,
SUM(REPLACE(REPLACE(REPLACE(structure_reserve,'$',''),',',''),'-',''))AS structure_reserve
FROM job_tbl
WHERE
job_status NOT IN(2,4,6,7,9) AND
insurance_carrier !=0 AND
FROM_UNIXTIME(date_of_loss,'%m') = MONTH(NOW()) AND
FROM_UNIXTIME(date_of_loss,'%Y') = YEAR(NOW())
GROUP BY insurance_carrier
) T