SQL Pivot on subset - sql

I have the following result set:
Type | Method | Amount
Type1 Cash Amount
Type1 Check Amount
Type2 Cash Amount
Type2 Check Amount
Type3 Cash Amount
Type3 Check Amount
And I want to make it look like this:
Type | Cash | Check
Type1 Amount Amount
Type2 Amount Amount
Type3 Amount Amount
How can I achieve this in T-SQL (2005 syntax ok)? I need to pivot by type (1, 2, 3...)

Here's an attempt at PIVOT:
select *
from YourTable
PIVOT (sum(amount) FOR Method in (Cash,Check)) as Y
Given that it's just two columns, could try with a join:
select
type
, cash = a.amount
, check = b.amount
from yourtable a
full join yourtable b on a.type = b.type
where a.method = 'cash' or b.method = 'Check'

Or better yet:
select
Type
, Cash = sum(case when Method = 'Cash' then Amount end)
, Check = sum(case when Method = 'Check' then Amount end)
from yourtable
group by
Type
Add an ELSE 0 to the CASE statements if appropriate.
This form is more flexible than the PIVOT operator and doesn't require a FULL JOIN. Just straight aggregation.

Related

How to pivot a table in sql and sum the amounts?

I have a table called test_table. This table looks like below
id
type
value
1
tax
10
1
premium
21
1
tax
3
1
correction
4.5
2
premium
15
I would like to "pivot" this table and make it look like below
id
premium
tax
correction
1
21
13 (=10+3)
4.5
2
15
NULL
NULL
create columns by type (premium, tax and correction)
sum the amounts by type and by id
With my basic sql knowledge, I have no idea how to build this query. Can you help me with this?
You may try the following pivot query:
SELECT
id,
SUM(CASE WHEN type = 'premium' THEN value ELSE 0 END) AS premium,
SUM(CASE WHEN type = 'tax' THEN value ELSE 0 END) AS tax
SUM(CASE WHEN type = 'correction' THEN value ELSE 0 END) AS correction
FROM yourTable
GROUP BY id
ORDER BY id;
Note that the above will report zero for those cells having entry in the source table.
In MS Sql Server, the PIVOT syntax should be sufficiant for this.
select *
from (
select id, [type], value
from test_table
) src
pivot (
sum(value)
for [type] in ([premium], [tax], [correction])
) pvt
order by id

Create SQL statement with mulitple AND

I have a problem with creating right SQL request.
This is my table:
item warehouse amount
item1 A 1
item1 B 5
item2 A 9
item2 B 2
item3 A 1
item3 A 0
item4 B 1
I would like to display all items that:
-Are in warehouse A in number less than 2
-Are in watehouse B in number grater than 0
At the same time.
I would expect item1 will be displayed.
My code so far is:
SELECT item, warehouse , amount
FROM XXXX
WHERE
(warehouse = B AND amount>0)
AND
(warehouse = A AND amount<2)
I know that warehouse = B AND warehouse = A will never happened, but i do not have any idea where to go from here.
I'am new to SQL, but i have feeling that i need to use GRUPBY
Any help ?
You can use aggregation. Use where to get either condition. Then check that both are met. Assuming that there is one row per item per warehouse, you can use:
SELECT item
FROM XXXX
WHERE (warehouse = 'B' AND amount > 0) OR
(warehouse = 'A' AND amount < 2)
GROUP BY item
HAVING COUNT(*) = 2;
Note that this does not return the amounts. If you want that as well, then pivot the data using conditional aggregation:
SELECT item,
SUM(CASE WHEN warehouse = 'B' THEN amount END) as b_amount,
SUM(CASE WHEN warehouse = 'A' THEN amount END) as a_amount
FROM XXXX
WHERE (warehouse = 'B' AND amount > 0) OR
(warehouse = 'A' AND amount < 2)
GROUP BY item
HAVING COUNT(*) = 2;

total and group multiple column values in a single query

I am looking to get a summary of multiple states from the same column.
select c.brand
sum amount as total
from charges as c
where c.invoive_id is not null
and c.paid = true
group by c.brand
gets me the sum of all completed purchases grouped by brand.
I want to have a separate column in the same query, summed by brand for "c.paid = false"
so I will have:
Brand Total(true) Total(false)
b_one 25 12
b_two 38 16
You seems to have a simple conditional aggregation statement -
SELECT c.brand
,SUM(CASE WHEN c.paid = 'true' THEN amount END) as Total(true)
,SUM(CASE WHEN c.paid = 'false' THEN amount END) as Total(false)
from charges as c
where c.invoive_id is not null
group by c.brand
You don't say which database you are using so I'll assume PostgreSQL. You can usually use a CASE clause to do this. For example:
select
c.brand,
sum(case when c.paid then 1 else 0 end) as total_true,
sum(case when c.paid then 0 else 1 end) as total_false
from charges as c
where c.invoive_id is not null
group by c.brand
In databases that support boolean types, you can often do:
select c.brand,
sum(c.paid) as num_true,
sum(not c.paid) as num_falst
from charges as c
where c.invoive_id is not null
group by c.brand

Selecting multiple rows of a column in a SQL Server query

I have a table, let's call it Case the case table contains basic information about a case, such as the CaseNumber and the CaseOwner.
In a separate table, CaseDetails a number of phone numbers associated with a particular case are stored. The Type column within CaseDetails represents the type of phone number e.g. Home, mobile or work. These two tables link on CaseNumber.
More clearly:
Case
CaseNumber CaseOwner
------------------------
1 Bob
2 Jim
3 Gary
CaseDetails
CaseNumber Detail Type
----------------------------------
1 0123456789 1
1 1111111111 2
2 2222222222 1
1 0101001011 3
2 1234123412 2
3 0000011111 1
3 1231231231 2
I want to be able to write a query that can pull back the basic details of a case, as well as ALL of the associated phone numbers.
In my head I imagined the query to go something like the following
Select
CaseNumber, CaseOwner,
Detail where Type = 1, Detail where Type = 2, Detail where Type = 3
From
Case
Join
CaseDetails on Case.CaseNumber = CaseDetails.CaseNumber
That way each individual Detail could be extracted from the CaseDetails table using the type column. However this is syntactically incorrect and won't execute.
How exactly would I construct a query to extract this information? I can't seem to find the information on this on Google as I'm not sure what to search for.
The whole point of this is so that I can find all of the associated numbers for a particular case and store them in one location.
This is what I want the final output to look like
CaseNumber CaseOwner Detail1 Detail2 Detail3
-------------------------------------------------------------------
1 Bob 0123456789 1111111111 0000011111
You can try below using CASE WHEN expression
Select a.CaseNumber, CaseOwner, max(case when Type = 1 then detail end) as as detail1, max(case when Type = 2 then detail end) as detail2, max(case when Type = 3 then detail end) as detail3
From Case a
Join CaseDetails b on a.CaseNumber = b.CaseNumber
group by a.CaseNumber, CaseOwner
OR you can use PIVOT
with cte as
(
Select a.CaseNumber, CaseOwner, type, detail
From Case a
Join CaseDetails b on a.CaseNumber = b.CaseNumber
group by a.CaseNumber, CaseOwner
)
select casenumber, caseowner,pv.*
from cte pivot(max(detail) for type in (1,2,3)) as pv
You can use conditional aggregation:
Select c.CaseNumber, c.CaseOwner,
max(case when cd.type = 1 then cd.Detail end) as detail_1,
max(case when cd.type = 2 then cd.Detail end) as detail_2,
max(case when cd.type = 3 then cd.Detail end) as detail_3
From Case c Join
CaseDetails cd
on c.CaseNumber = cd.CaseNumber
group by c.CaseNumber, c.CaseOwner;
EDIT:
You can also do this using outer apply:
select c.*, cd.*
from case c outer apply
(select max(case when cd.type = 1 then cd.Detail end) as detail_1,
max(case when cd.type = 2 then cd.Detail end) as detail_2,
max(case when cd.type = 3 then cd.Detail end) as detail_3
from CaseDetails cd
where c.CaseNumber = cd.CaseNumber
) cd;
use pivot
select CaseNumber,CaseOwner,
[1] as detail1,
[2] as detail2 ,
[3] as detail3
from
(select c1.CaseNumber,c1.CaseOwner,c2.Detail,c2.Type
From Case c1
Join CaseDetails c2
on c1.CaseNumber = c2.CaseNumber
) src
PIVOT
(
max(Detail) for Type in ([1],[2],[3])
) pvt

Make a grouping and transforming query Oracle

I have a test table:
category   type  quantities
 a      1    100
 a      2    150
 b      2    45
 b      3    68
 b      1    72
 c      2    90
 c      3    39
It is assume that only 3 types appeared. My goal is select out there categories, and quantities of each type. Result should like:
category   type1   type2   type3
 a      100    150    0
 b      72     45    68
 c      0     90    39
I'm trying with union, but I think it is redundant and not briefness:
select category, sum(type1)type1, sum(type2)type2 ,sum(type3) type3 from
(
select category, sum(quantities) type1, 0 type2, 0 type3 from test where type=1 group by category
union all
select category, 0 type1, sum(quantities) type2, 0 type3 from test where type=2 group by category
union all
select category, 0 type1, 0 type2, sum(quantities) type3 from test where type=3 group by category
) group by category;
What can I do to shorten my query? Thank you for any suggestions.
That is simple conditional aggregation:
select
category,
nvl(sum(case when type = 1 then quantities end), 0) as type1,
nvl(sum(case when type = 2 then quantities end), 0) as type2,
nvl(sum(case when type = 3 then quantities end), 0) as type3
from mytable
group by category
order by category;
Also known as a pivot table -- see http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html