Making a select for a two select sql/oracle - mysql

I want to join join 2 select in single query :
Here are the two queries.
SELECT player_id, SUM(score) score
FROM (
SELECT id_p1 player_id, score_p1 score
FROM matchs
UNION ALL
SELECT id_p2, score_p2
FROM matchs
) q
GROUP BY player_id
AND
SELECT player_id, SUM(score) score
FROM (
SELECT id_p1 player_id, score_p2 score
FROM matchs
UNION ALL
SELECT id_p2, score_p1
FROM matchs
) q
GROUP BY player_id
Thank you !

Try this
SELECT table1.player_id, table1.score score1, table2.score score2,
abs(table1.score - table2.score) difference
FROM (
SELECT player_id, SUM(score) score
FROM (
SELECT player1_id player_id, score_p1 score FROM matchs
UNION ALL
SELECT player2_id , score_p2 FROM matchs
) q GROUP BY player_id
) table1
INNER JOIN
(
SELECT player_id, SUM(score) score
FROM (
SELECT player1_id player_id, score_p2 score FROM matchs
UNION ALL
SELECT player2_id , score_p1 FROM matchs
) q GROUP BY player_id
) table2 ON table1.player_id = table2.player_id
SQL Fiddle Demo

Ideally, one would perform this operation using a FULL JOIN:
SELECT COALESCE(t1.player1_id, t2.player2_id)
SUM(COALESCE(t1.score_p1,0) + COALESCE(t2.score_p2,0))
FROM table_name t1
FULL JOIN table_name t2 ON t1.player1_id = t2.player2_id
GROUP BY COALESCE(t1.player1_id, t2.player2_id)
However, sadly MySQL does not have native support for such a join operation. Instead, one can simulate it by making a UNION between a LEFT JOIN and a RIGHT JOIN, then aggregating:
SELECT p, SUM(s) FROM (
SELECT t1.player1_id p, SUM(t1.score_p1 + IFNULL(t2.score_p2,0)) s
FROM table_name t1
LEFT JOIN table_name t2 ON t1.player1_id = t2.player2_id
GROUP BY t1.player1_id
UNION
SELECT t2.player2_id, SUM(IFNULL(t1.score_p1,0) + t2.score_p2)
FROM table_name t1
RIGHT JOIN table_name t2 ON t1.player1_id = t2.player2_id
GROUP BY t2.player2_id
) t GROUP BY p
See it on sqlfiddle.

Related

MySQL-condition on partition size

table1 has 3 columns in my database: id, category, timestamp. I need to query the newest 3 rows from each category:
WITH ranked_rows AS
(SELECT t.*, ROW_NUMBER() OVER (PARTITION BY category ORDER BY t.timestamp DESC) AS rn
FROM table1 AS t)
SELECT ranked_rows.* FROM ranked_rows WHERE rn<=3
now I need to add one more condition: select only from the partitions which have at least 3 rows. how to add this condition?
here is another way:
select * from (
SELECT t.*
, ROW_NUMBER() OVER (PARTITION BY category ORDER BY t.timestamp DESC) AS rn
, count(*) OVER (PARTITION BY category) AS cnt
FROM table1 AS t
) t
WHERE rn<=3 and cnt>= 3
You could make another CTE of only the categories matching your condition, then join to that:
WITH ranked_rows AS
(
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY category ORDER BY t.timestamp DESC) AS rn
FROM table1 AS t
),
categories AS
(
SELECT category
FROM table1
GROUP BY category
HAVING COUNT(*) >= 3
)
SELECT r.* FROM ranked_rows AS r
JOIN categories AS c USING (category)
WHERE r.rn <= 3;

SQL - Difficult Query

I want to do a query where for each diagnostic code - ID (this is a column), select the name of the most common medication - p_name (another column) used to treat that condition i.e., the medication name that more often appears associated to prescriptions (table) for that diagnosis.
This is the structure of my prescription table:
| p_name | lab | doctor_VAT | date_timestamp | ID | dosage | prescription_description |
I started by making a query to count the tuple pairs p_name and ID:
SELECT DISTINCT p.ID,
p.p_name,
COUNT(*) OVER (PARTITION BY p.p_name, p.ID) AS Cnt
FROM prescription AS p
ORDER BY Cnt DESC
And then to this I tried to apply the "greatest_n_per_group" problem to this
(SQL select only rows with max value on a column):
FROM (SELECT DISTINCT p.ID,
p.p_name,
COUNT(*) OVER (PARTITION BY p.p_name, p.ID) AS Cnt
FROM prescription AS p
ORDER BY Cnt DESC) as Tabela
INNER JOIN(
SELECT Tabela2.ID, MAX(Tabela2.Cnt)
FROM (SELECT DISTINCT p.ID,
p.p_name,
COUNT(*) OVER (PARTITION BY p.p_name, p.ID) AS Cnt
FROM prescription AS p
ORDER BY Cnt DESC) as Tabela2
GROUP BY Tabela2.ID
)
But this produces errors, am I going at this the right the way? do you suggest a different method?
Since your MySQL supports Window function, You can simply use -
SELECT ID, p_name
FROM (SELECT ID, p_name, RANK() OVER(PARTITION BY ID ORDER BY CNT DESC) RNK
FROM (SELECT ID,
p_name,
COUNT(*) CNT
FROM prescription
GROUP BY ID,
p_name
) T1
) T2
WHERE RNK = 1
You need FROM ( ) T in this case T is the table name alias for the FROM subquery clause
FROM (SELECT DISTINCT p.ID,
p.p_name,
COUNT(*) OVER (PARTITION BY p.p_name, p.ID) AS Cnt
FROM prescription AS p
ORDER BY Cnt DESC) as Tabela
INNER JOIN(
SELECT Tabela2.ID, MAX(Tabela2.Cnt)
FROM (SELECT DISTINCT p.ID,
p.p_name,
COUNT(*) OVER (PARTITION BY p.p_name, p.ID) AS Cnt
FROM prescription AS p
ORDER BY Cnt DESC) as Tabela2
GROUP BY Tabela2.ID
) T
SELECT
p1.ID,
(SELECT TOP 1 p2.p_name
FROM prescription AS p2
WHERE p2.ID=p1.ID
GROUP BY p2.p_name
ORDER BY count(*) DESC) as MostUsed
FROM prescription AS p1
GROUP BY p1.ID
Above is for MSSQL, below is for MySQL
SELECT
p1.ID,
(SELECT p2.p_name
FROM prescription AS p2
WHERE p2.ID=p1.ID
GROUP BY p2.p_name
ORDER BY count(*) DESC
LIMIT 1) as MostUsed
FROM prescription AS p1
GROUP BY p1.ID
dbfiddle

How to get the maximum and minimum values in each group as well as their times?

Let's say I have a table MyTable with the columns Id, NumericValue and UTCTimestamp. I'm trying to group the results of my table MyTable by the hour of their timestamp and return the maximum NumericValuefor each group with its associated timestamp as well as the minimum NumericValue for each group with its associated timestamp value.
For now, I'm able to achieve the first part of my problem with the following query:
SELECT
HOUR(t.UTCTimestamp) AS `Hour`,
t.NumericValue AS MaximumValue,
t.UTCTimestamp AS MaximumValueTime
FROM MyTable t
INNER JOIN (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MAX(t2.NumericValue) AS NumericValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) maxNumericValue ON HOUR(t.UTCTimestamp) = maxNumericValue.`Hour` AND t.NumericValue = maxNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp);
Which was inspired by this answer.
Here's an MVCE.
How could I also show the minimum value for each group as well as the timestamp associated to it?
Starting from MySQL 8.0 you could use ROW_NUMBER:
WITH cte AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY HOUR(UTCTimestamp)
ORDER BY UTCTimestamp ASC) AS rn
,ROW_NUMBER() OVER(PARTITION BY HOUR(UTCTimestamp)
ORDER BY UTCTimestamp DESC) AS rn2
FROM MyTable
)
SELECT HOUR(c1.UTCTimestamp),
c1.ID, c1.NumericValue, c1.UTCTimestamp, -- min row
c2.ID, c2.NumericValue, c2.UTCTimestamp -- max row
FROM cte c1
JOIN cte c2
ON HOUR(c1.UTCTimestamp) = HOUR(c2.UTCTimestamp)
AND c1.rn=1
AND c2.rn2=1
ORDER BY HOUR(c1.UTCTimestamp) ASC;
DBFiddle Demo
You can join to MyTable twice (and only use one aggregating subquery)
SELECT bounds.`Hour`
, minT.NumericValue AS MinValue
, minT.UTCTimestamp AS MinTime
, maxT.NumericValue AS MaximumValue
, maxT.UTCTimestamp AS MaximumValueTime
FROM (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`
, MAX(t2.NumericValue) AS maxValue
, MIN(t2.NumericValue) AS minValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) bounds
LEFT JOIN MyTable minT ON bounds.`Hour` = HOUR(minT.UTCTimestamp)
AND bounds.minValue = minT.NumericValue
LEFT JOIN MyTable maxT ON bounds.`Hour` = HOUR(maxT.UTCTimestamp)
AND bounds.maxValue = maxT.NumericValue
;
Apply the same technique but with minimum:
select a.*, b.MinimumValueTime from (
SELECT
HOUR(t.UTCTimestamp) AS `Hour`,
t.NumericValue AS MaximumValue,
t.UTCTimestamp AS MaximumValueTime
FROM MyTable t
INNER JOIN (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MAX(t2.NumericValue) AS NumericValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) maxNumericValue ON HOUR(t.UTCTimestamp) = maxNumericValue.`Hour` AND t.NumericValue = maxNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp))a
join
(
SELECT
HOUR(t.UTCTimestamp) AS `Hour`,
t.NumericValue AS MinimumValue,
t.UTCTimestamp AS MinimumValueTime
FROM MyTable t
INNER JOIN (
SELECT HOUR(t2.UTCTimestamp) AS `Hour`, MIN(t2.NumericValue) AS NumericValue
FROM MyTable t2
GROUP BY HOUR(t2.UTCTimestamp)
) minNumericValue ON HOUR(t.UTCTimestamp) = minNumericValue.`Hour` AND t.NumericValue = minNumericValue.NumericValue
GROUP BY HOUR(t.UTCTimestamp))b on a.hour=b.hour

Merging multiple similar query

I can get the result from multiple but simple queries but I would like to merge them further as sub queries.
All sub queries are going to be similar to this one-
SELECT COUNT(count) AS acc1 FROM (SELECT COUNT(table.colname) AS count
FROM tablename GROUP BY tablename.sumcol HAVING count=1) as access1
likewise others will be
SELECT COUNT(count) AS acc2 FROM (SELECT COUNT(table.colname) AS count
FROM tablename GROUP BY tablename.sumcol HAVING count=2) as access2
You could use UNION ALL for get both the results in the same result set
SELECT 'acc1' , COUNT(count)
FROM ( SELECT COUNT(table.colname) AS count
FROM tablename G
ROUP BY tablename.sumcol
HAVING count=1) access1
UNION ALL
SELECT 'acc2', COUNT(count)
FROM (SELECT COUNT(table.colname) AS count
FROM tablename
GROUP BY tablename.sumcol
HAVING count=2) access2
I have addedd 'acc1' and 'acc2' literal value for a better result reading but you can avoid it
do the fact you have only a rows for both the query , if you need the two result on the same row, you can use a cross join (cartesian product)
SELECT COUNT(count) as count_acc1, T.count2
FROM ( SELECT COUNT(table.colname) AS count1
FROM tablename G
GROUP BY tablename.sumcol
HAVING count=1) access1
CROSS JOIN (
SELECT COUNT(count) as count2
FROM (SELECT COUNT(table.colname) AS count
FROM tablename
GROUP BY tablename.sumcol
HAVING count=2) access2 ) T

MySQL Subquery SUM Limit

I'm trying to do an subquery with SUM() and LIMIT. This works fine with the following code:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = '1'
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1
But I want to do it of course dynamically and with the current row ID.
I changed the Query to the following:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
This will give the following error:
Unknown column 'p.id' in 'where clause'
Any ideas how to make it working?
Unfortunately, MySQL limits the scope of table aliases. Oracle is another database that does this.
You can phrase your query as a complicated join:
select t1.id, sum(t2.number)
from t1 p join
t2
on p.id = t2.u_id
where 30 >= (select count(*)
from t2 t22
where t22.u_id = t2.u_id and
t22.time <= t2.time
)
group by t1.id;
Or you can do this with variables:
select p.id, sum(number)
from t1 p join
(select t2.*,
#rn := if(#u = t2.u_id, #rn + 1, if((#u := t2.u_id) is not null, 1, 0)) as rn
from t2
(select #u := 0, #rn := 0) vars
order by t2.u_d, time
) t2
on p.id = t2.u_id
where rn <= 30
group by p.id;
why not just change p.id to t1.id? I'm pretty sure it's because you are aliasing t1 in the first select, and it isn't defined in the subquery. Try an inner join instead.
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
INNER JOIN t1 p
on u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
Try this:
SELECT id, temp2.sum_number as test
FROM t1 p
INNER JOIN
(
SELECT SUM(number) as sum_number, temp.u_id
FROM (
SELECT number, u_id
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS temp2 ON temp2.u_id = p.id
I moved subqueries in the join part, so i can access to p.id in the subquery.