Is it possible to convert this SQL into a JOIN?
SELECT (SELECT t2.id
FROM items t2
WHERE t2.user_id = items.user_id
ORDER BY [a list of cols that aren't stated here]
LIMIT 1) AS id
FROM items
WHERE company_name = '....'
GROUP BY user_id
Why both? Just use FIRST_VALUE():
SELECT DISTINCT col3,
FIRST_VALUE(col4) OVER (PARTITION BY col3 ORDER BY col1)
FROM tbl
WHERE col2;
Related
I have a complex mysql query where one of the Select fields is Min(value). Since all the 'values' are unique, is there also a way to get found min value's row id along?
In other words if we simplify the query to this question, it is like this:
SELECT t1.name, MIN(t2.value) AS minval
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY id_user
How can i now know which t2.id was chosen for lowest t2.value for particular user? Thank you!
Use ROW_NUMBER() to find the first value of each id_user
You can replace * with the fields you need
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY t2.id_user ORDER BY t2.value) as rnk
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
) as X
WHERE X.rnk = 1
Maybe this simple, dont know how complex your statement is:
SELECT name,value,id
FROM(
SELECT t1.name,t2.value,t2.id
FROM table1 t1
LEFT JOIN table2 t2
ON t2.id_user = t1.id
GROUP BY t2.id,id_user
ORDER BY t1.name,t2.id asc) as test
GROUP BY name;
This question already has answers here:
Get top n records for each group of grouped results
(12 answers)
Closed 6 years ago.
I'd like to select all rows from a table which contain 50 most frequent values of the column. I tried to use such a join, but it seems my choice of LEFT JOIN is wrong. The inner part of the statement seems fine. What should I change in my statement?
SELECT col1, col2
FROM tbl as t1
LEFT JOIN (
SELECT id
FROM tbl
WHERE id > 123
AND id < 987654
GROUP BY col1
ORDER BY COUNT(id) DESC
LIMIT 50
) AS t2
ON t1.id = t2.id
Rather than a JOIN, have you tried using an IN operator as part of your WHERE clause?
For example...
SELECT col1, col2
FROM tbl as t1
WHERE t1.id IN (
SELECT id
FROM tbl
WHERE id > 123
AND id < 987654
GROUP BY col1
ORDER BY COUNT(id) DESC
LIMIT 50
)
Right join should work if your subquery is correct, returning any matching rows of t1 to t2 (as opposed to all rows of t1 and the matching t2's or nulls):
SELECT col1, col2
FROM tbl as t1
RIGHT JOIN (
SELECT id
FROM tbl
WHERE id > 123
AND id < 987654
GROUP BY col1
ORDER BY COUNT(id) DESC
LIMIT 50
) AS t2
ON t1.id = t2.id
I realize my query was OK, I just wanted to join on col1, not id :)
SELECT col1, col2
FROM tbl as t1
LEFT JOIN (
SELECT col1
FROM tbl
WHERE id > 123
AND id < 987654
GROUP BY col1
ORDER BY COUNT(id) DESC
LIMIT 50
) AS t2
ON t1.col1 = t2.col1
I have two tables, tbl1(col1, col2, col3), tbl2(col1). I need to replace the data of tbl1.col1 with the data from tbl2.col1. My problem is there is no common field to join the two tables. Is it possible to write a query to do the update?
This should work. I'm not really sure what kind of data you have where there's no way to link Table2 and Table1, though:
WITH T1 AS
(
SELECT
RN = ROW_NUMBER() OVER (ORDER BY NULL)
,Col1
FROM
Tbl1
)
,T2 AS
(
SELECT
RN = ROW_NUMBER() OVER (ORDER BY NULL)
,Col1
FROM
Tbl2
)
UPDATE
T1
SET
Col1 = T2.col1
FROM
T1
INNER JOIN
T2
ON T1.RN = T2.RN
I have fairly complicated join query from which I want to select a few rows around a result with a certain id.
The query currently looks something like this:
WITH results AS
(
SELECT t1.id, t1.position, t1.points, t2.name
ROW_NUMBER() OVER(ORDER BY t1.position ASC, t1.points DESC) AS rn
FROM Table1 t1
JOIN Table2 t2 ON t1.id = t2.Table1id
/* Several more joins here, some of which limit the result set */
)
SELECT * FROM results
WHERE rn < ( SELECT rn+3 FROM results WHERE id = #someid )
AND rn > ( SELECT rn-3 FROM results WHERE id = #someid )
Is there a better way to solve this? Most of all I'm worried about performance with these multiple calls to a possibly huge CTE.
The query is run on a SQL 2008 server.
Maybe pull the joins out of the CTE.
That way the query optimizer has a chance filter out rows before processing the joins.
WITH results AS
(
SELECT t1.id, t1.position, t1.points
, ROW_NUMBER() OVER(ORDER BY t1.position ASC, t1.points DESC) AS rn
FROM Table1 t1
)
SELECT results.id, results.position, results.points, t2.name
FROM results
JOIN Table2 t2 ON t2.id = results.Table1id
/* Several more joins here */
WHERE rn < ( SELECT rn+3 FROM results WHERE id = #someid )
AND rn > ( SELECT rn-3 FROM results WHERE id = #someid )
You could use another cte to help form the filter:
WITH results AS (
SELECT
t1.id
, t1.position
, t1.points
, t2.name
, ROW_NUMBER() OVER (ORDER BY t1.POSITION ASC, t1.points DESC) AS rn
FROM Table1 t1
JOIN Table2 t2
ON t1.id = t2.Table1id
/* Several more joins here, some of which limit the result set */
),
filter AS (
SELECT
rn
FROM results
WHERE id = #someid
)
SELECT
*
FROM results
WHERE rn < ( SELECT rn + 3 FROM filter )
AND rn > ( SELECT rn - 3 FROM filter )
If I have a table with two columns, name and timestamp, and a bunch of rows that will have shared names. How do I select the most recent row of each set of rows that shares the same name?
Thanks!
SELECT name, MAX(timestamp) FROM Table1 GROUP BY name
EDIT: Based on the comment, please try the following:
SELECT name, timestamp, col3, col4
FROM Table1 t1
WHERE timestamp = (SELECT MAX(t2.timestamp)
FROM Table1 t2
WHERE t1.name = t2.name);
Added by Mchl
Version with no dependent subquery (should perform better)
SELECT
t1.name, t1.timestamp, t1.col3, t1.col4
FROM
Table1 AS t1
CROSS JOIN (
SELECT
name, MAX(timestamp) AS timestamp
FROM
Table1
GROUP BY
name
) AS sq
USING (name,timestamp)
Then you need a subquery:
SELECT columns
FROM Table1 t1
WHERE row_id = (SELECT row_id
FROM table1 t2
WHERE t1.name = t2.name
ORDER BY timestamp DESC
LIMIT 1)
GROUP BY name
Edited, forgot the group by name