I have an ingredients translations table this form (some columns have been removed for simplicity, but still required in the result)
| id | name | ingredient_id | language |
| 1 | Water | 11 | en |
| 2 | Bell pepper | 12 | en |
| 3 | Sweet pepper | 12 | en |
I'm trying to build a query to retrieve just one single ingredient translation per ingredient like this (expected result)
| id | name | ingredient_id |
| 1 | Water | 11 |
| 2 | Bell pepper | 12 |
So far now I'm trying to do it with this query
select it1.*
from ingredient_translations it1
left outer join ingredient_translations it2
on it1.ingredient_id = it2.ingredient_id
and it1.id < it2.id
where it1.language = 'es'
but it's now giving the expected results :/
flag
I'm using postgresql, though I was trying to do this using joins so I can device a cross-db (Postgresql - MySQL) solution.
Please, any insight will be apreciated!!! :D
WITH CustomerCTE (
SELECT t1.*,ROW_NUMBER() OVER (PARTITION BY ingredient_id ORDER BY id DESC) AS RN
FROM ingredient_translations t1
INNER JOIN ingredient_translations t2 ON t1.ingredient_id = t2.ingredient_id
)
SELECT * FROM CustomerCTE WHERE RN = 1
ORDER BY id;
Use ROW_NUMBER() over partition.
Query
select id,name,ingredient_id,language from
(
select id,name,ingredient_id,language,
row_number() over
(
partition by ingredient_id
order by id
) rn
from tbl_Name
)t
where t.rn < 2;
SQL Fiddle
Related
Mysql version: 8.0.21
I am lookig of get the latest value of each "TableData" which has the type "fruit".
Table Name: TableNames
_________________________________________
| id | name | id_group | type |
|-----------------------------------------|
| 0 | AppleGroup | apple | fruit |
| 1 | BananaGroup | banana | fruit |
| 2 | OtherGroup | other | other |
Table Name: TableData
__________________________
| id | id_group | value |
|--------------------------|
| 0 | apple | 12 |
| 1 | banana | 8 |
| 2 | apple | 3 | <--get latest
| 3 | banana | 14 |
| 4 | banana | 4 | <--get latest
With this Query I get all the items, but I am looking for the lastest of each.
I already tried to group by and order by, but the problem is that I first need to order by and then group by, seems that's not possible in Mysql.
SELECT
n.name,
d.value
FROM TableNames n
INNER JOIN
(
SELECT *
FROM TableData
) d ON d.`id_group` = n.`id_group`
WHERE type = 'fruit'
Expected ouput:
_____________________
| name | value |
|---------------------|
| AppleGroup | 3 |
| BananaGroup | 4 |
Without ROW_NUMBER(), because you can be on an older version of MySQL (before 8.0), you can create an inner join with the max(id):
SELECT
TableNames.name,
TableData.value
FROM
TableData
INNER JOIN (
SELECT
id_group,
MAX(id) as max
FROM TableData
GROUP BY id_group) x ON x.id_group = TableData.id_group
INNER JOIN TableNames on TableNames.id_group = TableData.id_group
WHERE x.max = TableData.id
see: DBFIDDLE
On MySQL 8+, we can use ROW_NUMBER():
WITH cte AS (
SELECT tn.name, tn.id_group, td.value,
ROW_NUMBER() OVER (PARTITION BY td.id_group ORDER BY td.id DESC) rn
FROM TableNames tn
INNER JOIN TableData td
ON td.id_group = tn.id_group
WHERE tn.type = 'fruit'
)
SELECT name, value
FROM cte
WHERE rn = 1
ORDER BY id_group;
For optimization, you may consider adding the following index to the TableData table:
CREATE INDEX idx ON TableData (id_group);
Note that on InnoDB, MySQL will automatically include id at the end of the index, hence the index is (id_group, id). This should let MySQL efficiently do the join in the CTE and also compute ROW_NUMBER.
An SqlFiddle showcasing sample data for my use case is here: http://sqlfiddle.com/#!9/ae57c5d/6
I have a table category (id, title) containing a list of categories, and a table item(id,name,category_id) with a foreign key category_id that is pointing to a category, and cannot be NULL.
If I now wanted to select the latest item from each category, I could do that by running the following query:
SELECT item.id, item.name, category.title
FROM category
JOIN (
SELECT MAX(id) AS max_id, category_id
FROM item
GROUP BY category_id
) AS i_max ON (i_max.category_id = category.id)
JOIN item ON (item.id = i_max.max_id)
ORDER BY item.id DESC
That gets me this:
+----+------------+-------+
| id | name | title |
+----+------------+-------+
| 15 | Sydney | City |
| 10 | Tesla | Car |
| 5 | Pear | Fruit |
+----+------------+-------+
But how would I write the query if I wanted 3 latest items from each category?
My expected output in this case would be something like this (order of categories in the output is irrelevant; order of items should be descending when focusing on any given category from the output):
+----+------------+-------+
| id | name | title |
+----+------------+-------+
| 15 | Sydney | City |
| 14 | London | City |
| 13 | Helsinki | City |
| 10 | Tesla | Car |
| 9 | Ferrari | Car |
| 8 | Mitsubishi | Car |
| 5 | Pear | Fruit |
| 4 | Watermelon | Fruit |
| 3 | Apple | Fruit |
+----+------------+-------+
Assuming you are using MySQL 8+, you could use ROW_NUMBER here:
WITH cte AS (
SELECT i.id, i.name, c.title,
ROW_NUMBER() OVER (PARTITION BY c.title ORDER BY i.id DESC) rn
FROM category c
INNER JOIN item i ON i.category_id = c.id
)
SELECT id, name, title
FROM cte
WHERE rn <= 3
ORDER BY title, id DESC;
If you upgrade DB to 8+ as mentioned, you'll be able to use analytic functions such as DENSE_RANK()
SELECT id, name, title
FROM
(
SELECT i.id, i.name, c.title,
DENSE_RANK() OVER (PARTITION BY i.category_id ORDER BY i.id DESC ) AS dr
FROM category c
JOIN item i
ON i.category_id = c.id
) t
WHERE dr <= 3
ORDER BY t.id DESC
Demo
The results with the ties(the values with the same ranking) also included in the result set for the case with using DENSE_RANK() function, while for ROW_NUMBER() it doesn't.
I know that the title sounds horrible but I have no idea how to summarize it better. I'm pretty sure that somebody had the same problem before but I couldn't find anything. RDBMS: MySQL.
Problem:
I have the following (simplified) table:
+------+------------+---------------------------------+
| name | date | score |
+------+------------+---------------------------------+
| A | 01.01.2015 | 1 |
| A | 01.02.2015 | 3 |
| A | 01.03.2015 | 4 |
| B | 01.01.2015 | 3 |
| B | 01.02.2015 | 4 |
| B | 01.03.2015 | 5 |
| C | 01.01.2015 | 1 |
| C | 01.02.2015 | 2 |
| C | 01.03.2015 | 3 |
+------+------------+---------------------------------+
There is no unique constraint or PK defined.
The table represents a highscore of a game. Every day the score of all players are inserted with values that are: name, points, now(),...
The data represent a snapshot of the score of each player at a specific time.
I want the most recent entry for each user only but only for the highest X players. So the result should look like
+------+------------+---------------------------------+
| name | date | score |
+------+------------+---------------------------------+
| A | 01.03.2015 | 4 |
| B | 01.03.2015 | 5 |
+------+------------+---------------------------------+
C doesn't appear since he's not in the top 2 (by score)
A appears with the most recent row (by date)
B appears, like A, with the most recent row (by date) and because he is in the top 2
I hope it becomes clear what I mean.
Thanks in advance!
I understand that what you need is to first select the X players who've gotten the highest score and then get their latest performance. In this case, you should do this:
SELECT *
FROM tablename t
JOIN
(
SELECT t.name, max(t.date) as max_date
FROM tablename t
JOIN
(
SELECT name
FROM
(
SELECT name, max(score) as max_score
FROM table_name
GROUP BY name
) all_highscores
ORDER BY max_score DESC
LIMIT X
) top_scores
ON top_scores.name = t.name
GROUP BY t.name
) top_last
on t.name = top_last.name
and t.date = top_last.date;
I have two tables: I am doing a join and wish to return a query with multiple codenames listed for each GenEx prescription brand. However it looks like the way im doing the join causes it to timeout.
Drugs:
ID | GenEx | CodeName | Desc
----------------------------
1 | Cipro | Dolvo |
2 | Ludavil | Ymir |
3 | Cipro | Alpha |
Medicine:
ID | GenEx | Price |
----------------------------
1 | Cipro | 4.99 |
2 | Ludavil | 12.99 |
3 | Benazol | 5.00 |
I wish to return:
1. GenEx->Cipro, CodeName=>Dolvo,Alpha, Price->4.99
2. GenEx->Ludavil, CodeName=>Ymir, Price->12.99
myquery which never completes:
SELECT GenEx, Price
GROUP_CONCAT(CodeName) as CodeName
FROM (`Drugs` d)
JOIN `Medicine` m ON `m`.`GenEx` = `d`.`GenEx`
WHERE GenEx
IN (
SELECT DISTINCT GenEx
FROM Drugs
WHERE codeName IN ('Alpha'))
)
GROUP BY `GenEx`;
Now updated the aswer as per the last update in the question.
Try this code:
SELECT d.`GenEx`, d.`CodeName`, d.`Price`,
GROUP_CONCAT(d.`CodeName`) as CodeName
FROM Drugs d
JOIN Medicine m
ON m.`GenEx` = d.`GenEx`
AND d.`GenEx`
IN (
SELECT DISTINCT `GenEx`
FROM drugs
WHERE codeName IN ('Alpha'))
)
GROUP BY d.`GenEx`;
And let me know what you get now.
inventory
+------------------+-------------------+------------+
| DVD | replacement_price | stock |
+------------------+-------------------+------------+
| Pi | 9.99 | 500 |
| Dune | 29.99 | 100 |
| Heathers | 4.99 | 20 |
| Jaws | 19.99 | 500 |
| Mulholland_Drive | 39.99 | 50 |
| Waking_Life | 29.99 | 200 |
+------------------+-------------------+------------+
rented
+-----------------+-----------+------------------+
| subscriber | queue_nbr | DVD |
+-----------------+-----------+------------------+
| Bob | 1 | Mulholland_Drive |
| Bob | 2 | Jaws |
| Chey | 1 | Pi |
| Chey | 2 | Heathers |
| Jamie | 2 | Mulholland_Drive |
| Jamie | 4 | Dune |
| Jamie | 1 | Jaws |
| Jamie | 3 | Waking_Life |
| Nora | 4 | Jaws |
| Nora | 2 | Mulholland_Drive |
| Nora | 3 | Dune |
| Nora | 1 | Waking_Life |
+-----------------+-----------+------------------+
I want to return ONLY the subscriber(s) with the priciest movie queue (think Netflix DVD replacement costs if you lost all the movies you had out at a given time). I've used MAX() rather than TOP, LIMIT or ROWNUM because the query needs to be as db-independent as possible and must return multiple subscribers in the event of a tie. Using the tables above, the result should be
+---------+
| highest |
+---------+
| Jamie |
| Nora |
+---------+
After much searching and experimentation, I've come up with code that works, but it seems to my novice eyes bloated and inefficient, both in quantity of code and execution.
Would anyone mind refactoring and explaining your code?
My code:
SELECT z.subscriber highest
FROM
(SELECT MAX(price) max_price
FROM (
SELECT subscriber_name subscriber, SUM(replacement_price) price
FROM inventory i
INNER JOIN rented r
ON i.DVD = r.DVD
GROUP BY subscriber
) x
) y
INNER JOIN
(
SELECT subscriber_name subscriber, SUM(replacement_price) price
FROM inventory i
INNER JOIN rented r
ON i.DVD = r.DVD
GROUP BY subscriber
) z
ON z.price = y.max_price
If you want to return only those with the max total, then you could use the following which works in both MySQL and SQL Server. It is not any more concise than your current query though:
select subscriber
from inventory i
inner join rented r
on i.dvd = r.dvd
group by subscriber
having sum(replacement_price) = (select max(TotalCost)
from
(
select sum(replacement_price) TotalCost
from inventory i
inner join rented r
on i.dvd = r.dvd
group by subscriber
) p);
If you are using SQL Server, then I would suggest implementing windowing functions, similar to this:
select subscriber
from
(
select subscriber,
rank() over(order by sum(replacement_price) desc) rnk
from inventory i
inner join rented r
on i.dvd = r.dvd
group by subscriber
) src
where rnk = 1
See SQL Fiddle with Demo
SELECT z.subscriber
FROM(
SELECT RANK() OVER(ORDER BY SUM(replacement_price)) subscriber_rank,
r.subscriber subscriber,
SUM(replacement_price) totalReplacementPrice
FROM inventory i
INNER JOIN rented r ON i.dvd = r.DVD
GROUP BY subscriber
) z
WHERE z.subscriber_rank = 1
Some of your column names are different in you query from you sql sample, so I've used the column names given in the demo tables. I use the rank function in the inner query to find the order of all of the people ordering by the sum of the replacement_price. Then select the row(s) where the rank is 1.
Rank is available in both MS Sql Server and Oracle. To go much further than that as #bluefeet says you will need to give more detail as to which database you are targetting.