First of all, sorry for my bad English :)
I have following example table data:
id name state amount
1 name1 open 2
1 name1 open 3
1 name1 closed 4
2 name2 open 5
2 name2 closed 8
2 name2 closed 4
I want to aggregate amount data for each state (open or closed) and name (name1 or name2)
something like this:
id name open(sum amount) closed(sum amount)
1 name1 5(2+3) 4
2 name2 5 12(8+4)
Can somebody help me?
Apart from the already chosen answer another way of doing this is :
SELECT
id
,name
,SUM( IF( state = 'open' ,amount ,0 ) ) open_total
,SUM( IF( state = 'closed' ,amount ,0 ) ) closed_total
FROM
`data`
WHERE
1
GROUP BY
name
SELECT id, name,
SUM(CASE WHEN state="open" THEN amount else 0 END) AS `open`,
SUM(CASE WHEN state="closed" THEN amount else 0 END) AS `closed`
FROM <yourtablename>
GROUP BY id;
Mind the special quotes in the derived column names, they cannot be replaced by a different type of quotes.
Related
I have a table like this
Id title parentId subparentId itemcategory
1 service cat1 0 0 C
2 service cat2 0 0 C
3 service subcat1 1 0 S
4 service subcat2 2 0 S
5 Item 1 1 0 I
5 Item 2 1 3 I
6 Item 3 2 4 I
I need an out put like this
service cat1
Item 1
service subcat1
Item 2
service cat2
service subcat2
Item 3
Ie, list shows the items ( category ,subcategory,Items ) in the order ascending order and if the items have any subcategory it should come under the subcategory
I think you should try something like:
SELECT
t1.title,
t2.title,
t3.title
FROM table t1
LEFT JOIN table t2 ON t1.id = t2.parentId
LEFT JOIN table t3 ON t2.id = t3.subparentId
WHERE t1.itemcategory = 'C'
AND t2.itemcategory = 'S'
AND t3.itemcategory = 'I'
;
For this case:
you should join your third table (item), directly with first table (service cat), not with second like in my example.
It's a complicated problem because there can be only one dimension in the sql query result.
But we can do a little trick here
SELECT *
FROM
(
SELECT
id,
title,
parentId,
subparentId,
itemcategory,
IF(
parentId = 0 AND subparentId = 0,
id * 10000,
IF(
subparentId = 0,
parentId * 10000 + 100 - id,
parentId * 10000 + subparentId * 100 + id
)
) AS itemOrder
FROM
table1
) allOrder
ORDER BY allOrder.itemOrder
SQL Fiddle: http://sqlfiddle.com/#!9/5f711/1/0
Increase the multiplier if you've got more rows.
Another way of doing it: http://sqlfiddle.com/#!9/bbf4d/1
(there is no need for a multiplier here)
select
concat(indent1, indent2, title) as title
from (
select
if(parentid>0,parentid,id) as id1,
case itemcategory
when 'C' then -1
when 'S' then id
when 'I' then if(subparentid>0,subparentid,0)
end as id2,
case itemcategory
when 'C' then -1
when 'S' then -1
when 'I' then id
end as id3,
case itemcategory
when 'C' then ''
when 'S' then '- - '
when 'I' then '- - '
end as indent1,
case itemcategory
when 'C' then ''
when 'S' then ''
when 'I' then '- - '
end as indent2,
title
from table1
order by id1,id2,id3
) allitems
Half of this code is for indenting so you get a nicer view. It's exactly like you requested (items are all indented equally even if they are not in the same level) but you can Fiddle with it yourself.
You can also add id1,id2,id3 in the first select to see how the order is done. The outside select is only done for viewing the title alone with indenting.
The result will be:
title
----------------------
service cat1
- - - - Item 1
- - service subcat1
- - - - Item 2
service cat2
- - service subcat2
- - - - Item 3
I need to group the table during my query, and up until know I was doing that after querying - with the code as my group is quite complicated. But with the new data it appears to take minutes, and I'm thinking is there better way.
My current query results in this:
FKId | Name | A | B | C
1 Alpha 2 3 2
1 Beta 2 5 7
2 Alpha 8 1 10
2 Beta 7 -5 6
2 Gamma 1 2 3
And I convert it to this:
FKId | Alpha[A] | Alpha[B] | Alpha[C] | Beta[A] | Beta[B] | Beta[C] | Gamma[A] | Gamma[B] | Gamma[C]
1 2 3 2 2 5 7
2 8 1 10 7 -5 6 1 2 3
Is it possible to do with SQL? (and I assume it should be much faster than if I do this with code)
The names can be anything
I have very big number of colums A, B, C (like 20 - 30). The number of result columns can easily go to thousands as average project has about 100 names.
I have like 10-20 columns that I should group by, but doing a single group by FKId is fine - these columns are the same.
We use different SQL DBs, so I cannot use specific functions like PIVOT. I know that we used MySQL, MsSQL and SQLite a lot
We use NHibernate if it makes any difference.
I would also honor the solution done for MySQL if specific functions are used. We use it in 80% and it will already greatly improve the average performance if I could do that at least for MySQL.
Basically, you want to transpose the data. Here is what you can try. It should work across all databases but you need to know the columns A, B, C, etc beforehand:
create table my_table (
fkid integer,
name varchar(10),
a integer,
b integer,
c integer
);
insert into my_table values(1,'alpha',2,3,2)
,(1,'beta',2,5,7)
,(2,'alpha',8,1,10)
,(2,'beta',7,-5,6)
,(2,'gamma',1,2,3);
select fkid
, max(case when name = 'alpha' then a else null end) as alphaa
, max(case when name = 'alpha' then b else null end) as alphab
, max(case when name = 'alpha' then c else null end) as alphac
, max(case when name = 'beta' then a else null end) as betaa
, max(case when name = 'beta' then b else null end) as betab
, max(case when name = 'beta' then c else null end) as betac
, max(case when name = 'gamma' then a else null end) as gammaa
, max(case when name = 'gamma' then b else null end) as gammab
, max(case when name = 'gamma' then c else null end) as gammac
from my_table
group by fkid;
I'm trying to denormalize a result set so that I have one record per ID. This is a list of patients with multiple comorbidities. The data currently looks like this:
ID Disease
1 Asthma
1 Cancer
1 Anemia
2 Asthma
2 HBP
And I need it to look like this:
ID Disease1 Disease2 Disease3
1 Asthma Cancer Anemia
2 Asthma HBP <NULL or Blank>
I researched Pivot, but all of the examples I saw used aggregate functions which wouldn't apply.
I have added the row_number function and tried self joins like the following:
case when rownum = 1 then Disease else NULL end Disease1,
case when rownum = 2 then Disease else NULL end Disease2,
case when rownum = 3 then Disease else NULL end Disease3
However, this produces the following:
ID Disease1 Disease2 Disease3
1 Asthma NULL NULL
1 NULL Cancer NULL
1 NULL NULL Anemia
2 Asthma NULL NULL
2 NULL HBP NULL
Any suggestions would be greatly appreciated. I would really like to find a way to accomplish this without having a monstrous block of code (which is what I ended up with when trying to do it). Thanks!
You can use MAX to compact the rows:
select
id,
max(case when rownum = 1 then Disease end) Disease1,
max(case when rownum = 2 then Disease end) Disease2,
max(case when rownum = 3 then Disease end) Disease3
from (
select
id,
disease,
rownum = ROW_NUMBER() OVER (partition by id order by id)
from your_table
) sub
group by id
Sample SQL Fiddle
i have table named chat_users with columns:
id | username | status | time_mod | views
Here is an example of UPDATE with CASE statement that works brilliantly:
$db->exec("UPDATE `proba13`.`chat_users`
SET `username` = CASE id
WHEN 4 THEN 'Jie'
WHEN 5 THEN 'Mie'
WHEN 6 THEN 'Pres'
END,
`status` = CASE id
WHEN 4 THEN '1'
WHEN 5 THEN '2'
WHEN 6 THEN '3'
END
WHERE id IN (4,5,6)");
QUESTION:
can anybody please give me an example of SELECT with CASE statement on the same table ?
regards and
Thank you in advance!
This will return the same results as your updated table (however, obviously without making any changes to it):
SELECT id,
CASE id
WHEN 4 THEN 'Jie'
WHEN 5 THEN 'Mie'
WHEN 6 THEN 'Pres'
ELSE username
END AS username,
CASE id
WHEN 4 THEN 1
WHEN 5 THEN 2
WHEN 6 THEN 3
ELSE status
END AS status,
time_mod,
views
FROM proba13.chat_users
Try this one
SELECT (CASE WHEN
id =4 THEN 'Jie'
WHEN id =5 THEN 'Mie'
WHEN id =6 THEN 'Pres'
END ) `username` ,
(CASE WHEN
id= 4 THEN '1'
WHEN id= 5 THEN '2'
WHEN id= 6 THEN '3'
END ) `status` FROM `chat_users`
WHERE id IN (4,5,6)
let say i have one table, which have data like:
name status
bob single
bob single
jane null
tina null
shane married
i want if status "single or data null" it means single. so if data empty script can read it as single and can count together.
so i can show result like:
Single Married
3 1
i have tried with this and it doesnt work:
SELECT SUM(IF(status='single',1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
Use:
SELECT SUM(CASE WHEN x.status = 'single' OR x.status IS NULL THEN 1 ELSE 0 END) AS single,
SUM(CASE WHEN x.status = 'married' THEN 1 ELSE 0 END) AS married
FROM (SELECT DISTINCT
t.name,
t.status
FROM YOUR_TABLE t) x
If you know there are only 'single', 'married', and null as options, this will work:
SELECT SUM(IF(status!='married',1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
Otherwise try
SELECT SUM(IF(status='single' OR status is null,1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
SELECT SUM(IF(status='single' OR status IS NULL,1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table