Join multiple select queries SQL - sql

I have two queries with different where clauses,and I need to join both the query to get a single result table.
First query:
SELECT
players.id,player_name,count(matches.winner) as wintotal
FROM
matches, players
WHERE
matches.winner = players.id
GROUP BY
players.id;
It returns these results:
id | player_name | wintotal
45 | Vijay | 2
43 | Rahul | 1
46 | Shinoy | 1
48 | Sunil | 2
44 | Adarsh | 4
Second query :
SELECT
players.id, player_name, count(*) as totalgames
FROM
matches, players
WHERE
matches.winner = players.id or matches.loser = players.id
GROUP BY
players.id;
Returns:
id | player_name | Total Matches
45 | Vijay | 4
43 | Rahul | 2
46 | Shinoy | 4
48 | Sunil | 2
44 | Adarsh | 6
47 | Pranjal | 2
In these two queries, the where clause is different for both queries and the last column is different.
First query returns total wins by players
Second query returns total matches played by player
How can I join both queries to get both columns wins and total matches in single query?
Expected output:
id | player_name | Total Matches | wintotal
45 | Vijay | 4 | 2
43 | Rahul | 2 | 1
46 | Shinoy | 4 | 1
48 | Sunil | 2 | 2
44 | Adarsh | 6 | 4
47 | Pranjal | 2 | 0
Thanks

try:
select players.id,
player_name,
count(case when matches.winner=players.id then 1 end) as wintotal ,
count(*) as totalgames
from matches
join players
on matches.winner=players.id or matches.loser=players.id
group by players.id,
player_name;

Check This.
select id , player_name ,Total_Matches , wintotal
(
select players.id,player_name,count(matches.winner) as wintotal from matches,players where matches.winner=players.id
group by players.id
) A,
(
select players.id,player_name,count(*) as Total_Matches from matches,players where matches.winner=players.id or
matches.loser=players.id
group by players.id
) B
where A.id=B.ID

Related

Sql join does not return some rows with groupBy

I am trying to learn sql.I do some practices.I created a table which called Student.
Id | Name | Amount
1 | Jone | 100
2 | Jack | 200
3 | Emily | 300
4 |Haaland | 500
7 |Ted | 700
I also created Orders table like that:
Id | Name | Amount | Dıscount
1 | Jone | 100 | 10
2 | Jack | 112 | 20
3 | Emily | 300 | 30
4 |Haaland | 500 | 50
5 |Jack | 88 | 12
7 |Ted | 150 | 235
My query is:
select a1.Id Id ,a1.Name Name, a1.Amount Amount , sum(a2.discount)
from student a1
left outer join orders a2
on a1.Id=a2.Id
and a1.Name=a2.Name
and a1.Amount = a2.Amount
group by a1.Id, a1.Name, a1.Amount
Result:
Id | Name | Amount | Dıscount
1 | Jone | 100 | 10
3 | Emily | 300 | 30
4 |Haaland | 500 | 50
2 | Jack | 200 | null
7 | Ted | 700 | null
I get null value for the jack row.I have to use a1.Amount=a2.Amount because I remove amount constraint Ted'discount also appears.
Expected Result :
Id | Name | Amount | Dıscount
1 | Jone | 100 | 10
3 | Emily | 300 | 30
4 |Haaland | 500 | 50
2 | Jack | 200 | 32
7 | Ted |700 | null
I think the logic you want is to pre-aggregate the orders of each name in a subquery, then join by name and amount:
select s.id , s.name, s.amount, o.discount
from student s
left join (
select name, sum(amount) amount, sum(discount) discount
from orders
group by name
) o on o.name = s.name and o.amount = s.amount
What is the confusion? In one row you have:
id name amount
2 Jack 200
And in the other:
id name amount
2 Jack 112
Your join requires equality on all three columns. The amounts don't match, so there is no match for Jack's row and the amount is null.
Your question is not clear on what you actually want to do, so I'll stop here.
The amount for Jack does not match (200 in Student, 88 and 112 in Orders), so nothing can be joined ON a1.Amount = a2.Amount for that record. However, Please be advised that even if one of the values in Amount does match, the GROUP BY function will still not know which Amount you want associated with 'Jack'.

How to do a narrow to wide transformation of data when there are no key names

I have a data set that looks like this:
school_id | class_id | recess_num | student_id
----------------------------------------------
27 | 6 | 2 | 12
27 | 6 | 2 | 53
27 | 6 | 2 | 23
27 | 6 | 2 | 47
27 | 14 | 2 | 6
27 | 14 | 2 | 51
27 | 14 | 2 | 42
27 | 14 | 2 | 60
The idea is that certain students from different classes go out for recess at the same time. A couple of important points:
The same number of students from each class go out at the same time
The number of students from each class that go out each time is always the same (let's say 4 at a time)
I would like to create a wide table representation of this data where all the students that are out at each recess are captured in a single row. Since the number of students is always the same, I want to create new columns for each of the students:
school_id | class_id | recess_num | student_1 | student_2 | student_3 | student_4
---------------------------------------------------------------------------------
27 | 6 | 2 | 12 | 53 | 23 | 47
27 | 14 | 2 | 6 | 51 | 42 | 60
What is the best way to accomplish this using only a SQL query?
You can do conditional aggregation:
select
school_id,
class_id,
recess_num,
max(case when rn = 1 then student_id end) student_1,
max(case when rn = 2 then student_id end) student_2,
max(case when rn = 3 then student_id end) student_3,
max(case when rn = 4 then student_id end) student_4
from (
select
t.*,
row_number()
over(partition by school_id, class_id, recess_num order by student_id) rn
from mytable t
) t
group by
school_id,
class_id,
recess_num
The inner query ranks students within groups of school/class/recess, ordered by increasing id. Then the outer query pivots the data, using conditional aggregation.
Note that this does not produces exactly the same ordering of students in the columns as your expected result. However, this seems like a more consistent method to order the students by id (your expected result does not seem consistent in that regard).
Demo on DB Fiddle:
school_id | class_id | recess_num | student_1 | student_2 | student_3 | student_4
--------: | -------: | ---------: | --------: | --------: | --------: | --------:
27 | 6 | 2 | 12 | 23 | 47 | 53
27 | 14 | 2 | 6 | 42 | 51 | 60
select
school_id,
class_id,
recess_num,
case when student_id=12 then student_id end as student1,
case when student_id=53 then student_id end as student2,
case when student_id=23 then student_id end as student3,
case when student_id=47 then student_id end as student4,
from table
group by
school_id,
class_id,
recess_num

eSQL multiple join but with conditions

I've 3 tables as under
MERCHANDISE
+-----------+-----------+---------------+
| MERCH_NUM | MERCH_DIV | MERCH_SUB_DIV |
+-----------+-----------+---------------+
| 1 | car | awd |
| 1 | car | awd |
| 2 | bike | 1kcc |
| 3 | cycle | hybrid |
| 3 | cycle | city |
| 4 | moped | fixie |
+-----------+-----------+---------------+
PRIORITY
+----------+-----------+---------+---------+------------+------------+---------------+
| CUST_NUM | SALES_NUM | DOC_NUM | BALANCE | PRIORITY_1 | PRIORITY_2 | PRIORITY_CODE |
+----------+-----------+---------+---------+------------+------------+---------------+
| 90 | 1000 | 10 | 23 | 1 | 6 | NO |
| 91 | 1001 | 20 | 32 | 3 | 7 | PRI |
| 92 | 1002 | 30 | 11 | 2 | 8 | LATE |
| 93 | 1003 | 40 | 22 | 5 | 9 | 1MON |
+----------+-----------+---------+---------+------------+------------+---------------+
ORDER
+----------+-----------+---------+---------+-----------+-----------+
| CUST_NUM | SALES_NUM | DOC_NUM | COUNTRY | MERCH_NUM | MERCH_DIV |
+----------+-----------+---------+---------+-----------+-----------+
| 90 | 1000 | 10 | INDIA | 1 | car |
| 91 | 1001 | 20 | CHINA | 2 | bike |
| 92 | 1002 | 30 | USA | 3 | cycle |
| 93 | 1003 | 40 | UK | 4 | moped |
+----------+-----------+---------+---------+-----------+-----------+
I want to join the left joined table from the last two tables with the first one such that the MERCH_SUB_DIV 'awd' appears only once for each unique combination of merch_num and merch_div
the code I came up with is as under, but I'm not sure how do I eliminate the duplicate row just for the awd
select
ROW#, MERCH.MERCH_NUMBER, ORDPRI.MERCH_NUMBER, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, ITEM_NUM, RANK, PRIORITY_1
from (
select
ROW_NUMBER() OVER(
PARTITION BY ORD.DOC_NUM, ORD.ITEM_NUM
ORDER BY ORD.DOC_NUM, ORD.ITEM_NUM ASC
) AS Row#,
ORD.CUST_NUM, PRI.CUST_NUM, ORD.MERCH_NUM, ORD.MERCH_DIV, PRI.BALANCE,
pri.DOC_NUM, pri.SALES_NUM, pri.PRIORITY_1, pri.PRIORITY_2
from ORDER as ORD
left join PRIORITY as PRI on ORD.DOC_NUM = PRI.DOC_NUM
and ORD.SALES_NUMBER = PRI.SALES_NUM
where country_name in ('USA', ‘INDIA’)
) as ORDPRI
left join MERCHANDISE as MERCH on ORDPRI.DIV = MERCH.DIV
and ORDPRI.MERCH_NUM = MERCH.MERCH_NUM
You have to use 'DISTINCT' keyword to get unique values, but if your 'Priority table' & 'Order table' contains different values for Same MERCH_NUM then the final result contains the repetation of the 'MERCH_NUM'.
SELECT DISTINCT M.MERCH_NUMBER, O.MERCH_NUMBER, O.CUST_NUM, BALANCE, SALES_NUM,ITEM_NUM,RANK,PRIORITY_1
FROM priority_table P
LEFT JOIN order_table O ON P.CUST_NUM = O.CUST_NUM AND P.SALES_NUM=O.SALES_NUM AND P.DOC_NUM = O.DOC_NUM
LEFT JOIN merchandise_table M ON M.MERCH_NUM = O.MERCH_NUM
A way around can be to add one new Row_Number() in the outermost query having Partition by MERCH_SUB_DIV + all the columns in the final list and then filter final results based on the New Row_Number() . Follows a pseudo code that might help:
select
-- All expected columns in final result except the newRow#
ROW#, MERCH_NUM, CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
from (
select
ROW#,
-- the new row number includes all column you want to show in final result
row_number() over ( PARTITION BY MERCH.MERCH_SUB_DIV ,
MERCH.MERCH_NUM, ORDPRI.MERCH_NUM, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
order by (select 1 )) as newRow# ,
MERCH.MERCH_NUM, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
from (
-- main query goes here
select
ROW_NUMBER() OVER(
PARTITION BY ORD.DOC_NUM --, ORD.ITEM_NUM
ORDER BY ORD.DOC_NUM ASC --, ORD.ITEM_NUM
) AS Row#,
ORD.CUST_NUM, ORD.MERCH_NUM, ORD.MERCH_DIV as DIV, PRI.BALANCE,
pri.DOC_NUM, pri.SALES_NUM, pri.PRIORITY_1, pri.PRIORITY_2
from #ORDER as ORD
left join #PRIORITY as PRI on ORD.DOC_NUM = PRI.DOC_NUM
and ORD.SALES_NUMBER = PRI.SALES_NUM
where country_name in ('USA', 'INDIA')
) as ORDPRI
left join #MERCHANDISE as MERCH on ORDPRI.DIV = MERCH.DIV
and ORDPRI.MERCH_NUM = MERCH.MERCH_NUM
) as T
-- final filter to get distinct values
where newRow# = 1
Sample code here .. Hope this helps!!

How to count all distinct rows?

If I have a table like below, how can I count and sum all distinct values?
student_name | section | score | class
-------------|---------|-------|-------
John | B | 32 | 8
Doe | B | 43 | 8
Jane | A | 33 | 8
Smith | A | 88 | 8
Pat | B | 99 | 9
The output I desire is following for each class. So for class 8 it would be:
section | num_records | score_total
---------|--------------|-------------
B | 2 | 75
A | 2 | 121
Total | 4 | 196
You could use GROUPING SETS:
SELECT COALESCE(section, 'Total') AS section,
COUNT(*) AS num_records,
SUM(score) AS score_total
FROM t
WHERE class = 8
GROUP BY GROUPING SETS (section, ())
ORDER BY section;
db<>fiddle demo
you could use union all and subquery
select section,count(*),sum(score)
from t
where class =8
group by section
union all
select 'Total',count(*),sum(score) from t
where class=8
demo
output
section count sum
A 2 121
B 2 75
Total 4 196

Pair entry of every nth row with entry of every (n+1)th row

I have a result table
id | name | wins
----+-------------------
57 | Paul | 10
64 | Sven | 9
62 | Peter | 9
59 | Marina | 8
58 | Carlos | 4
60 | Pamela | 3
61 | Marcus | 2
63 | Hank | 1
Where I want to pair every nth entry with every (n+1)th entry, such that the resulting table looks like that:
id | name | id | name
----+-------------------
57 | Paul | 64 | Sven
62 | Peter | 59 | Marina
58 | Carlos | 60 | Pamela
61 | Marcus | 63 | Hank
Which SQL statement would achieve that?
;WITH cte AS (
SELECT *,ROW_NUMBER() OVER (ORDER BY Wins DESC) as RowNum
FROM
#Table
)
SELECT *
FROM
cte c1
LEFT JOIN cte c2
ON c1.RowNum + 1 = c2.RowNum
WHERE
c1.RowNum % 2 <> 0
Generate a ROW_NUMBER to use, seeing you have a third Column replace (SELECT NULL) in the Order by statement with that third column.
Then select all rows that are Odd Row numbers (remainder of RowNum divided by 2 <> 0 ) and self join back to itself with RowNum + 1. If you have an odd number of Rows you might consider using LEFT JOIN so you don't drop off the 1 row that won't have a match.