Merging rows in SQL - php

My table looks like this:
Dept Wk1 Wk2
100 25 50
200 25 50
300 25 50
400 25 50
500 25 50
My results need to look like this:
Dept Wk1 Wk2
100 25 50
200 25 50
300 25 50
400 50 100
Things worth noting; the database is Pervasive PSQL10 and I'm using PHP to handle the results. I thought about doing this merge in PHP, but ideally if it could be done in the query that would save me the need for the extra code.
Reason for combining rows is that 2 depts will be treated as one when the data is pulled.
I think I'm overthinking it, but I've explored union, group by, and stuff (which I'm probably using incorrectly) and nothing is giving me what I need.
Any help or direction would be greatly appreciated, because what I've read so far addresses rows that have the same values, but not different.
Here is what my query actually looks like:
SELECT
dept_workcenter,
SUM(case when right(date_sequence,2) between 0 and 7 then hours_worked else 0 end) as wk1,
SUM(case when right(date_sequence,2) between 8 and 14 then hours_worked else 0 end) as wk2,
SUM(case when right(date_sequence,2) between 15 and 21 then hours_worked else 0 end) as wk3,
SUM(case when right(date_sequence,2) between 22 and 28 then hours_worked else 0 end) as wk4,
SUM(case when right(date_sequence,2) between 29 and 31 then hours_worked else 0 end) as wk5
FROM job_detail
WHERE job between '017079' AND '017207'
AND date_sequence BETWEEN '141200' and '141231'
AND dept_workcenter != ''
GROUP BY dept_workcenter
HAVING SUM(hours_worked) <> '0'
AND SUM(hours_worked) > '0.05';

You can use a case statement in the group by:
select (case when dept in (400, 500) then 400 else dept end) as dept,
sum(wk1) as wk1, sum(wk2) as wk2
from table t
group by (case when dept in (400, 500) then 400 else dept end)
order by dept;

So basically take the 500 and merge it with the 400?
SELECT Dept, SUM(Wk1) AS Wk1, SUM(Wk2) AS Wk2
FROM yourtable
GROUP BY Dept IN (400,500), Dept

This is not an uncommon problem in reporting. The typical method to handle this is to generate a temporary table in which you can modify the 500 to be 400, and then do a GROUP BY and SUM. This method will become more useful the more complicated your reporting becomes over time.
create table #DeptReptTable from select * from department;
update #DeptReptTable set Dept = 400 where Dept = 500;
select Dept, SUM(Wk1) Wk1, SUM(Wk2) Wk2 from #DeptReptTable group by Dept
drop table #DeptReptTable
Note: The # in front of the temp table is a Sybase-ism, which will create a table tied to the current SQL connection / session. I don't know if that magic works for Pervasive.

Related

SQL Server Case with Session

I have an issue where I'm trying to show a result based on a time frame being either greater than 24 hours, greater than 18 hours or less than 18 hours where a My query thus far is written as
SELECT MAX(CASE WHEN DATEDIFF(HH,DATEADD(SECOND, inc.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 24 then 2
WHEN DATEDIFF(HH,DATEADD(SECOND, inc.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 18 then 1
Else 0 End) as DIFFERENCE
FROM dbo.HELP_DESK as inc
WHERE inc.LOGIN_ID in "some user"
and NOT EXISTS (SELECT work.Description from dbo.WORKLOG as work WHERE
work.INCIDENT_NUMBER = inc.INCIDENT_NUMBER
and work.WORK_LOG_TYPE = '16000'
and work.WORK_LOG_SUBMITTER in "User Group")
UNION ALL
SELECT MAX(CASE WHEN DATEDIFF(HH,DATEADD(SECOND, chg.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 24 then 2
WHEN DATEDIFF(HH,DATEADD(SECOND, chg.ORIGINATION_DATE, '19700101'),DATEADD(hour,6,GETDATE())) > 18 then 1
Else 0 End) as DIFFERENCE
FROM dbo.INFRASTRUCTURE_CHANGE as chg
WHERE chg.ASLOGID in "some user"
and NOT EXISTS (SELECT work.Description from dbo.WORKLOG as work WHERE
work.CHANGE_ID = chg.CHANGE_ID
and work.WORK_LOG_TYPE = '31000'
and work.WORK_LOG_SUBMITTER in "User Group")
My output in this example is:
+------------+
| DIFFERENCE |
+------------+
| 2 |
| 2 |
+------------+
I have multiple values >24 so obviously due to the union Im showing two separate values correctly as 2. However, what I want to do is somehow group them so I have a single output of 2, 1 or 0 that I can then output to a PHP session.
some form of count or group by both seem to fail unless I'm incorrectly grouping. There's also probably a better way of doing this but I appear to be taking the long road round.
Appreciate any pointers in taking me forward.
A simple change from UNION ALL to UNION returned the single result I was after to output a session value

How to edit this mySQL so as to combine the rows of the same id into 1 instead of 3?

The following mySQL query gets data from 2 tables, alerts_data and alerts_list. The first table has the data of an alert, and the second has the description of the alert. So in the alerts_data there are multiple rows with the same alerts_data_id that is the same with the alerts_id of alerts_list.
What i want to achieve, is to display something like this
alert number 51, 5 clicked , 2 closed
alert number 57, 13 clicked, 3 closed, 8 waiting
using mySQL or PHP (i do not know if i can get this through plain mySQL)
So for now with my knowledge I can not display the data of alert 51 in one row, but because of the different alerts_data_status i have to show 3 rows for each.
How can I do it as above?
SELECT COUNT( alerts_data_id ) AS total, alerts_data_id, alerts_data_status, alerts_list.alerts_title
FROM alerts_data
JOIN alerts_list ON
alerts_data.alerts_data_id = alerts_list.alerts_id
GROUP BY alerts_data_id, alerts_data_status
//output
total - alerts_data_id - alerts_data_status - alerts_title
5 - 51 - clicked - alert number 51
2 - 52 - closed - alert number 51
13 - 57 - clicked - alert number 57
3 - 57 - waiting - alert number 57
8 - 57 waiting - alert number 57
Note: the alerts number are just examples, it can be any number
// alert_data
id - alerts_data_id - alerts_data_status
// alerts_list
alerts_id - alerts_name - alerts_text
Here's a sqlfiddle: http://sqlfiddle.com/#!9/c70c2/1
This may be an application for GROUP_CONCAT().
You first want a summary of your alerts by alerts_data_id and alerts_data_status. This is a little complex, because your sqlfiddle has a whole bunch of empty alerts_data_status strings. Here, I'm replacing those empty strings with `?'. (http://sqlfiddle.com/#!9/c70c2/23/0)
SELECT COUNT(*) AS alerts_count,
alerts_data_id,
CASE WHEN LENGTH(alerts_data_status) = 0 THEN '?'
ELSE alerts_data_status END AS alerts_data_status
FROM alerts_data
GROUP BY alerts_data_id, alerts_data_status
You then want to roll that up inside another query
SELECT SUM(a.alerts_count) total,
a.alerts_data_id, b. alerts_name,
GROUP_CONCAT( CONCAT(a.alerts_count, ': ', a.alerts_data_status)
ORDER BY a.alerts_data_status
SEPARATOR "; " ) detail
FROM (
SELECT COUNT(*) AS alerts_count,
alerts_data_id,
CASE WHEN LENGTH(alerts_data_status) = 0 THEN '?'
ELSE alerts_data_status END AS alerts_data_status
FROM alerts_data
GROUP BY alerts_data_id, alerts_data_status
) a
JOIN alerts_list b ON a.alerts_data_id = b.alerts_id
GROUP BY a.alerts_data_id, b.alerts_name
This will give you one row for each distinct alerts_data_id. Each alert is identified by its count, its id, and its name. (http://sqlfiddle.com/#!9/c70c2/26/0)
Then the row will contain a semicolon-separated list of the counts of the different alert status.
If i understand you well i think here is what you need;
SELECT
COUNT( alerts_data.id ) AS total,
ad.id,
(SELECT count(*) from alert_list al where al.alerts_id=ad.id and alerts_data_status='clicked') as clicked,
(SELECT count(*) from alert_list al where al.alerts_id=ad.id and alerts_data_status='closed') as closed,
(SELECT count(*) from alert_list al where al.alerts_id=ad.id and alerts_data_status='waiting') as waiting,
FROM alerts_data ad
GROUP BY ad.id
Was checking other answers and your SQLFIDDLE and thought this might be a nicer approach:
SELECT alerts_list.alerts_title,
SUM(CASE WHEN alerts_data_status = 'clicked' THEN 1 ELSE 0 END) AS clicked,
SUM(CASE WHEN alerts_data_status = 'closed' THEN 1 ELSE 0 END) AS closed,
SUM(CASE WHEN alerts_data_status = 'waiting' THEN 1 ELSE 0 END) AS waiting
FROM alerts_data
JOIN alerts_list ON alerts_data.alerts_data_id = alerts_list.alerts_id
GROUP BY alerts_list.alerts_title

Select max win series: sql query

MySQL
I have table, where i store user_matches and it result:
n_match id_user id_score
1 55 1
1 66 0
This mean, 'user with id=55 win match with id=1 to user with id=66'.
So, we have 10, 100, 1000 matches, where user win or lose to opponents:
n_match id_user id_score
1 55 1 (win)
1 66 0
2 55 0 (lose)
2 77 1
3 55 1 (win)
3 77 0
4 55 1 (win)
4 77 0
5 55 1 (win)
5 77 0
Ok. As u can see, user win 3 matches without losing (win series)- and that's what i need from my query.
Question: How could i get from this table the longest series of won matches? Is it possible without looping on sql side or server side- just from query?
Thx.
Edit: One of solution i just now understand,- to get all matches as string like 001010101111010101011, then split it into array of strings with separator '0' -> [1, 1, 1, 1111, ...] and just take the longest string length.
But in this case i have to write server side code =\ That's not good, but mb the fastest.
The best way to do this is to calculate the cumulative number of losses for any match. For a sequence of wins, this value is constant. You can then use group by to get the length of the longest such sequence.
This version of the query is database-neutral. It uses subqueries to get the counts:
select user_id, max(NumWinsInRow)
from (select user_id, cumlosses, count(*)-1 as NumWinsInRow
from (select m.*,
(select sum(case when id_score = 0 then 1 else 0 end) from user_matches m2 where m2.id_user = m.id_user and m2.n_match <= m.n_match
) as CumLosses
from user_matches m
) t
group by cumlosses, user_id
) t
group by user_id
This query should run faster if you have an index on user_matches(id_user, n_math, id_score).

php mysql sum issue

I want to generate a report to accumulate the total stock quantity that has been ordered by different branches in a month, and each branch will sum up the quantity by merged (GROUP BY) stock.
i trimmed up my database table for easy understanding as below:
Item Branch Order_Quantity
---------------------------------------
Pencil Branch-A 5
Ruler Branch-D 3
Staple Branch-C 12
Pencil Branch-A 5
Ruler Branch-B 3
Staple Branch-C 2
Pencil Branch-A 10
Ruler Branch-A 6
Staple Branch-D 1
for example, below is draft of expected outcome result:
Item Branch-A Branch-B Branch-C Branch-D
----------------------------------------------------------
Pencil 20 15 32 8
Ruler 12 0 40 10
Staple 4 8 5 0
and so on...
How can I use query to call the above result and assign each sum to their respective branch column?
below is my query:
SELECT `Item`, `Branch`, sum(`Order_Quantity`) FROM `table` GROUP BY `Item`
but when I call and loop the table, the result will show sum quantity to every branches
Item Branch-A Branch-B Branch-C Branch-D
----------------------------------------------------------
Pencil 75 75 75 75
Ruler 62 62 62 62
Staple 17 17 17 17
Hope someone can help for this.
thanks.
Try:
SELECT `Item`, `Branch`, sum(`Order_Quantity`) FROM `table` GROUP BY `Item`, `Branch`
This is some kind of PIVOT:
select item,
sum(case when branch = 'Branch-A' then order_Quantity else 0 end) as BranchA,
sum(case when branch = 'Branch-B' then order_Quantity else 0 end) as BranchB,
sum(case when branch = 'Branch-C' then order_Quantity else 0 end) as BranchC,
sum(case when branch = 'Branch-D' then order_Quantity else 0 end) as BranchD
from yourTable
group by item
assuming you have a finite number of branches you can create a query with sub selects for each "column" you wish to display (as per branch) with your sums, like so...
select
(select sum(order_quantity) from table where branch = 'Branch-A'),
(select sum(order_quantity) from table where branch = 'Branch-B'),
etc..
This is not a very elegant solution, but it will result in what you're looking for.
Otherwise you can follow the advice of the other posters which is more efficient from a sql standpoint but will not generate the columns you are hoping to see (as per your question).
SELECT SUM(Order_Quantity) AS CNT FROM `table` GROUP BY `Branch`;

How to rearrange the following data using php?

i retrieved the following data using sql query from mysql
TOTAL COMPUTER DATE GROUP
-----------------------------------------------
48 LAPTOP2 2009-08-19 1
77 LAPTOP2 2009-08-20 1
0 LAPTOP2 2009-08-21 1
15 LAPTOP1 2009-08-19 1
25 MAIN 2009-08-23 1
25 LAP3 2009-08-18 2
3 LAP3 2009-08-19 2
55 LAP3 2009-08-20 2
i would like to rearrange the data like using php
group computer 2009-08-18 2009-08-19 2009-08-20 2009-08-21 2009-08-22 2009-08-23
------------------------------------------------------------------------------------------------
1 LAPTOP2 0 48 77 0 0 0
1 LAPTOP1 0 15 0 0 0 0
1 MAIN 25
2 LAP3 25 3 55 0 0 0
Use the following query to pivot the data:
SELECT t.group,
t.computer,
MAX(CASE WHEN t.date = '2009-08-18' THEN t.total ELSE 0 END) AS '2009-08-18',
MAX(CASE WHEN t.date = '2009-08-19' THEN t.total ELSE 0 END) AS '2009-08-19',
MAX(CASE WHEN t.date = '2009-08-20' THEN t.total ELSE 0 END) AS '2009-08-20'
--, etc...
FROM TABLE t
GROUP BY t.group, t.computer
Your options are either to define each column for the data you are pivoting, or you can use MySQL's Prepared Statement syntax to dynamically create those columns.
I feel the need to point out that your example is inconsistent - for LAPTOP2, you have zero as the value for 2009-08-18, but the main value for that is blank. Neither have a record for that date. If you want these to show as blank/etc, change ELSE 0 END to ELSE NULL END in the CASE statements.

Categories