PostgreSQL select query 'join multiple rows to one row' - sql

I am new to PostgreSQL. My case is that I have a table where I store my data. The data come from a file as one row and are getting saved in the database as 5 rows. What I want is to make a SELECT statement where it will combine the 5 rows again into one.
e.g.
id id2 id3 year code value
4 1 1 1642 radio 30
4 1 1 1642 tv 56
4 1 1 1642 cable 67
4 1 1 1642 dine 70
I want to have a query where it will return the following:
id id2 id3 year radio tv cable dine
4 1 1 1642 30 56 67 70
The values of the code are becoming columns with values the actual values.
Is this possible?

You could use (SQL Fiddle):
SELECT m.id, m.id2, m.id3, m.year,
SUM(CASE WHEN m.code = 'radio' THEN m.value END) as radio,
SUM(CASE WHEN m.code = 'tv' THEN m.value END) as tv,
SUM(CASE WHEN m.code = 'cable' THEN m.value END) as cable,
SUM(CASE WHEN m.code = 'dine' THEN m.value END) as dine
FROM MyTable m
GROUP BY m.id, m.id2, m.id3, m.year

Related

Sqlite group by distinct count

I have table of customers operations:
date, client_id, gender
1 1 M
1 1 M
1 2 M
1 2 M
1 3 F
2 1 M
2 1 M
2 1 M
2 2 M
2 2 M
2 3 F
2 3 F
2 4 F
2 5 M
2 5 M
etc
Desired output is:
date, amount of males, (also need amount of females)
1 2 1
2 3 2
I need to group it by date, so i did it, then my goal is to find amount of each gender in each grouped group.
so i tried to do this to count amount of males:
sum(case when gender = 'M' then 1 else NULL end) as 'M%'
but its counted clients id 1 and 2 two times each, but i need to count it distinct.
On example above i expect this to return 2 because 2 male. But it return 4 because distinct construction doesnt work.
I tried this but it doesnt work and count '1' in result:
sum(distinct case when gender = 'M' then 1 else NULL end) as 'M%'
It's easier to count from the distinct rows of the table.
Also, use SQLite's feature to treat boolean expressions as 1 for true and 0 for false so you can sum them instead of using CASE expressions:
SELECT date,
SUM(gender = 'M') [amount of males],
SUM(gender = 'F') [amount of females]
FROM (SELECT DISTINCT date, client_id, gender FROM tablename)
GROUP BY date
See the demo.
You seem to want conditional count(distinct):
select date,
count(distinct case when gender = 'M' then client_id end) as count_m,
count(distinct case when gender = 'F' then client_id end) as count_f
from t
group by date;

Create a score card report based on match results in SQL

Here's my sample input of match results from a tournament and the result column indicates whether team 1 or team 2 won the game (0 stands for a draw).
score table -
-----------------
t1 t2 result
-----------------
us aus 1
aus sa 2
sa us 0
us nz 1
Desired output -
---------------------------------
team played won lost draw
---------------------------------
aus 2 0 2 0
us 3 2 0 1
nz 1 0 1 0
sa 2 1 0 1
Here's my solution that I came up with, but Is it possible to solve it without using a UNION operator?
select
t1 as team,
count(1) as played,
sum(case when result=1 then 1 else 0 end) as won,
sum(case when result=2 then 1 else 0 end) as lost,
sum(case when result=0 then 1 else 0 end) as draw
from
(select
t1,
t2,
result
from score
union
select
t2,
t1,
case when result=1 then 2
when result=2 then 1
else 0 end as result
from score
) t
group by t.t1
You could UNPIVOT your data via a CROSS APPLY and then perform the aggregation on the results
Example
Select Team
,played = count(1)
,won = sum(case when Val=1 then 1 else 0 end)
,lost = sum(case when Val=2 then 1 else 0 end)
,draw = sum(case when Val=0 then 1 else 0 end)
From score A
Cross Apply ( values (T1,Result )
,(T2,case when result=1 then 2 when result=2 then 1 else 0 end)
) B(Team,Val)
Group By Team
Results
team played won lost draw
aus 2 0 2 0
nz 1 0 1 0
sa 2 1 0 1
us 3 2 0 1

To select data from multiple records in SQL Server having a common ID

I need to select/concat data from 2 tables in SQL Server I'm using Left Join, but the data is returned as multiple records.
Below are the sample tables
Table1
Id Name Age
1 Sk 20
2 Rb 30
Table2
ID Bike Price Table1Id
1 RX 200 1
2 CD 250 1
3 FZ 300 1
4 R1 400 2
The desired output is
ID Name Age Bike1 Price1 Bike2 Price2 Bike3 Price3
1 Sk 20 RX 200 CD 250 FZ 300
2 Rb 30 R1 400 NULL NULL NULL NULL
A sample format of the query I'm using
SELECT A.ID, A.Name, B.Bike, B.Price FROM Table1 A LEFT JOIN Table2 B ON
A.id = B.Table1Id order by A.id
The output I'm getting from the above query is
ID Name Age Bike Price
1 Sk 20 RX 200
1 Sk 20 CD 250
1 Sk 20 FZ 300
2 Rb 30 R1 400
I need the data as one record for a particular ID and not multiple records (As seen in the desired output). Tired using offset, but offset will return only limited result not the entire records.
Any suggestions on how this can be achieved?
If you know the maximum number of bikes per person, you can use conditional aggregation:
SELECT ID, Name,
MAX(CASE WHEN seqnm = 1 THEN Bike END) as bike_1,
MAX(CASE WHEN seqnm = 1 THEN Price END) as price_1,
MAX(CASE WHEN seqnm = 2 THEN Bike END) as bike_2,
MAX(CASE WHEN seqnm = 2 THEN Price END) as price_2,
MAX(CASE WHEN seqnm = 3 THEN Bike END) as bike_3,
MAX(CASE WHEN seqnm = 3 THEN Price END) as price_3
FROM (SELECT A.ID, A.Name, B.Bike, B.Price,
ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY B.Price) as seqnum
FROM Table1 A LEFT JOIN
Table2 B
ON A.id = B.Table1Id
) ab
GROUP BY ID, Name,
ORDER BY id

SQL query sum of total corresponding rows

I have two tables as below. Caseid from first table is referenced in second table along with accidents. What I am trying to get total different accidents for a case type. Below two tables I documented sample data and expected result.
Table case:
caseId CaseType
1 AB
2 AB
3 AB
4 CD
5 CD
6 DE
Table CaseAccidents:
AccidentId caseID AccidentRating
1 1 High
2 1 High
3 1 Medium
4 1 LOW
5 2 High
6 2 Medium
7 2 LOW
8 5 High
9 5 High
10 5 Medium
11 5 LOW
Result should look like:
CaseType TotalHIghrating TotalMediumRating TotalLOWRating
AB 3 2 2
CD 2 1 1
DE 0 0 0
To get the sum of every rating, you can Use a SUM(CASE WHEN) clause, adding 1 by every record that match the rating.
In your question, you have pointed out that you want to see all distinct CaseType, you can get it by using a RIGHT JOIN, this will include all records of case table.
select case.CaseType,
sum(case when caseAccidents.AccidentRating = 'High' then 1 else 0 end) as TotalHighRating,
sum(case when caseAccidents.AccidentRating = 'Medium' then 1 else 0 end) as TotalMediumRating,
sum(case when caseAccidents.AccidentRating = 'LOW' then 1 else 0 end) as TotalLowRating
from caseAccidents
right join case on case.caseId = caseAccidents.caseID
group by case.CaseType;
+----------+-----------------+-------------------+----------------+
| CaseType | TotalHighRating | TotalMediumRating | TotalLowRating |
+----------+-----------------+-------------------+----------------+
| AB | 3 | 2 | 2 |
+----------+-----------------+-------------------+----------------+
| CD | 2 | 1 | 1 |
+----------+-----------------+-------------------+----------------+
| DE | 0 | 0 | 0 |
+----------+-----------------+-------------------+----------------+
Check it: http://rextester.com/MCGJA9193
Have you use case in a select clause before?
select C.CaseType,
sum(case when CA.AccidentRating = 'High' then 1 else 0 end)
from Case C join CaseAccidents CA on C.CaseId = CA.CaseId
group by C.CaseType
Please see this. Sample query of the table and also that result
create table #case(caseid int,casetype varchar(5))
insert into #case (caseid,casetype)
select 1,'AB' union all
select 2,'AB' union all
select 3,'AB' union all
select 4,'CD' union all
select 5,'CD' union all
select 6,'DE'
create table #CaseAccidents(AccidentId int, CaseId int,AccidentRating varchar(10))
insert into #CaseAccidents(AccidentId, CaseId, AccidentRating)
select 1,1,'High' union all
select 2,1,'High' union all
select 3,1,'Medium' union all
select 4,1,'Low' union all
select 5,2,'High' union all
select 6,2,'Medium' union all
select 7,2,'Low' union all
select 8,5,'High' union all
select 9,5,'High' union all
select 10,5,'Medium' union all
select 11,5,'Low'
My script
select c.casetype,
sum(case when ca.AccidentRating='High' then 1 else 0 end) as TotalHighRating,
sum(case when ca.AccidentRating='Medium' then 1 else 0 end) as TotalMediumRating,
sum(case when ca.AccidentRating='Low' then 1 else 0 end) as TotalLowRating
from #case c
Left join #CaseAccidents ca
on c.Caseid=ca.Caseid
group by c.casetype
Hope This could help!
Another approach using Pivot operator
SELECT casetype,
[High],
[Medium],
[Low]
FROM (SELECT c.casetype,
AccidentRating
FROM case c
LEFT JOIN CaseAccidents ca
ON ca.CaseId = c.caseid)a
PIVOT (Count(AccidentRating)
FOR AccidentRating IN ([High],
[Medium],
[Low]) ) p
Try This code once.
select casetype,
sum(case when ca.AccidentRating='High' then 1 else 0 end ) as TotalHIghrating,
sum(case when ca.AccidentRating='Medium' then 1 else 0 end ) as TotalMediumRating ,
sum(case when ca.AccidentRating='Low' then 1 else 0 end ) as TotalLOWRating
from #case c
left join #CaseAccidents ca on c.caseid=ca.CaseId
group by casetype

select from 2 tables with multiple counts

I have 2 tables I'm trying to join in a select query.
Table 1: Store, primary_key(id,store_num)
store_id store_num due_date manager_id
1 100 06-30-2024 user1
2 108 06-30-2018 user2
3 109 13-31-2014 user3
Table 2: Department, where status(A-applied,p-Pending)
store_id store_num dept_num status
1 100 201 A
1 100 202 A
1 100 203 P
1 100 204 A
1 100 205 P
1 100 206 A
Expecting to select store_id, store_num, due_date, manager_id, Applied count, pending count. The result is something looks like this.
store_id store_num due_date manager_id applied_count pending_count
1 100 06-30-2024 user1 4 2
I tried it and got where I am able to join and get it in multiple rows, But counts not working out for me. can some one help me how I can get the counts
select
store.store_id,
store.store_num,
store.due_date,
store.manager_id,
dept.status
from store as store
inner join department as dept on store.store_id = dept.store_id
and store.store_num = dept.store_num
Your query is half way done. You need to do an aggregation to get the values in different columns. This is a conditional aggregation, as shown here:
select s.store_id, s.store_num, s.due_date, s.manager_id,
sum(case when d.status = 'A' then 1 else 0 end) as Active_Count,
sum(case when d.status = 'P' then 1 else 0 end) as Pending_Count
from store s inner join
department as dept
on s.store_id = d.store_id and s.store_num = d.store_num
group by store.store_id, store.store_num, store.due_date, store.manager_id;
The expression:
sum(case when d.status = 'A' then 1 else 0 end) as Active_Count,
Is counting the rows where status = 'A'. It does so by assigning such rows a value of 1 and then summing up that value.