Grouped random order in SQL - sql

I have a table name Employees with two columns, case id and owner. I need to write a query to select random 5 caseids for every name in owner column.
Owners name are non sorted and also caseid are unique.
Also if anyone can explain using ranking over partition by in this case?
I tried this code but its not working using self join.
select t.*
from t
where t.id in (select top 5 id
from t as t2
where t2.name = t.name
order by Rnd(-Timer()*[ID])
);

I guess you have specify the table in the subquery:
select t.*
from t
where t.id in (select top 5 t2.id
from t as t2
where t2.name = t.name
order by Rnd(-Timer()*t2.[ID])
);

Related

SQL Server query showing most recent distinct data

I am trying to build a SQL query to recover only the most young record of a table (it has a Timestamp column already) where the item by which I want to filter appears several times, as shown in my table example:
.
Basically, I have a table1 with Id, Millis, fkName and Price, and a table2 with Id and Name.
In table1, items can appear several times with the same fkName.
What I need to achieve is building up a single query where I can list the last record for every fkName, so that I can get the most actual price for every item.
What I have tried so far is a query with
SELECT DISTINCT [table1].[Millis], [table2].[Name], [table1].[Price]
FROM [table1]
JOIN [table2] ON [table2].[Id] = [table1].[fkName]
ORDER BY [table2].[Name]
But I don't get the correct listing.
Any advice on this? Thanks in advance,
A simple and portable approach to this greatest-n-per-group problem is to filter with a subquery:
select t1.millis, t2.name, t1.price
from table1 t1
inner join table2 t2 on t2.id = t1.fkName
where t1.millis = (select max(t11.millis) from table1 t11 where t11.fkName = t1.fkName)
order by t1.millis desc
using Common Table Expression:
;with [LastPrice] as (
select [Millis], [Price], ROW_NUMBER() over (Partition by [fkName] order by [Millis] desc) rn
from [table1]
)
SELECT DISTINCT [LastPrice].[Millis],[table2].[Name],[LastPrice].[Price]
FROM [LastPrice]
JOIN [table2] ON [table2].[Id] = [LastPrice].[fkName]
WHERE [LastPrice].rn = 1
ORDER BY [table2].[Name]

SQL - Update last occurrence with select in clause

In Oracle, I would like do an update on a table for the last occurrence based on select in list, something like :
UPDATE table t1
set t1.fieldA = 0
where t1.id in (
select t2.id, max(t2.TIMESTAMP)
from table t2
where t2.id in (1111,2222,33333)
group by t2.id
);
This query does not works, I received an error "too many values".
Any ideas?
Thanks
Your subselect has 2(too many) fields so it cant't be compared with the id.
compare the timestamp with the max timestamp.
UPDATE table t1 set t1.fieldA = 0
where t1.TIMESTAMP = (select max(t2.TIMESTAMP) from table t2 where t2.id = t1.id )
and id in (1111,2222,33333)
I believe oracle supports multiple columns IN, so you could try:
UPDATE table t1
set t1.fieldA = 0
where
(t1.id,t1.timestamp) in ( select t2.id, max(t2.TIMESTAMP) from table t2 where t2.id in (1111,2222,33333) group by t2.id );
Essentially if you're providing a subquery to the right side of the IN that has a result set with two columns, then you have to provide the names of both the columns in brackets on the left side of the IN
Incidentally, I've never liked updating based on a max value if the requirement is that only one row be updated, as two rows with the same max value will both be updated. This kind of query is better:
Update table
Set fieldA=0
Where rowid in(
select rowid from (
select rowid, row_number() over(partition by id order by timestamp desc
) as rown from table
) where rown=1)
If, however, your primary key on the table includes the time stamp as part of the compound, then there is no concern of here being two rows with the same ID/timestamp.. it's just rarely the case!

Using MAX when selecting a high number of fields in a query

I understand some varieties of this question have been asked, but I could not find an answer to my specific scenario.
My query has over 50 fields being selected, and only one of them is an aggregate, using MAX(). On the GROUP BY clause, I would only like to pass two specific fields, name and UserID, not all 50 to make the query run. See small subset below.
SELECT
t1.name,
MAX(t2.id) as UserID,
t3.age,
t3.height,
t3.dob,
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id
LEFT JOIN table3 t3 ON t1.id = t3.id
GROUP BY t1.name, UserID
Is there any workaround or better approach to accomplish my goal?
The database is SQL Server and any help would be greatly appreciated.
Hmmm . . . What values do you want for the other fields? If you want the max() of one column for each id and code, you can do:
select t.*
from (select t.*, max(col) over (partition by id, code) as maxcol
from t
) t
where col = maxcol;
Given that id might be unique, you might want the maximum id as well as the other columns for each code:
select t.*
from (select t.*, max(id) over (partition by code) as maxid
from t
) t
where id = maxid;

Left Join with duplicate keys in the right table

I'm trying merging 2 tables as follow
SELECT * FROM T1
LEFT JOIN T2 ON T1.EMPnum = T2.EMPnum
The above works well but I need the joining to use only the first appearance of the common key EMPnum record in table T2 so that the query returns exactly the same number of rows as T1
Thanks Avi
SQL tables are inherently unordered, so there is no such thing as a "first" key. In most databases, you can do something like this:
with t2 as (
select t2.*, row_number() over (partition by EMPnum order by id) as seqnum
from t2
)
select *
from t1 left join
t2
on t1.EMPnum = t2.EMPnum and t2.seqnum = 1;
Here id is just any column that specifies the ordering. If none exist, you can use EMPnum to get an arbitrary row.

SQL - using a value in a nested select

Hope the title makes some kind of sense - I'd basically like to do a nested select, based on a value in the original select, like so:
SELECT MAX(iteration) AS maxiteration,
(SELECT column
FROM table
WHERE id = 223652
AND iteration = maxiteration)
FROM table
WHERE id = 223652;
I get an ORA-00904 invalid identifier error.
Would really appreciate any advice on how to return this value, thanks!
It looks like this should be rewritten with a where clause:
select iteration,
col
from tbl
where id = 223652
and iteration = (select max(iteration) from tbl where id = 223652);
You can circumvent the problem alltogether by placing the subselect in an INNER JOIN of its own.
SELECT t.iteration
, t.column
FROM table t
INNER JOIN (
SELECT id, MAX(iteration) AS iteration
FROM table
WHERE id = 223652
) tm ON tm.id = t.id AND tm.iteration = t.iteration
Since you're using Oracle, I'd suggest using analytic functions for this:
SELECT * FROM (
SELECT col,
iteration,
row_number() over (partition by id order by iteration desc) rn
FROM tab
WHERE id = 223652
) WHERE rn = 1
do it like this:
with maxiteration as
(
SELECT MAX(iteration) AS maxiteration
FROM table
WHERE id = 223652
)
select
column,
iteration
from
table
where
id = 223652
AND iteration = maxiteration
;
Not 100% sure on Oracle syntax, but isn't it something like:
select iteration, column from table where id = 223652 order by iteration desc limit 1
I would approach this problem in a slightly different way. You're basically looking for the row that has no other iterations greater than it. There are at least 3 ways I can think of to do this:
SELECT
T1.iteration AS maxiteration,
T1.column
FROM
Table T1
WHERE
T1.id = 223652 AND
NOT EXISTS
(
SELECT *
FROM Table T2
WHERE
T2.id = 223652 AND
T2.iteration > T1.iteration
)
Or...
SELECT
T1.iteration AS maxiteration,
T1.column
FROM
Table T1
LEFT OUTER JOIN Table T2 ON
T2.id = T1.id AND
T2.iteration > T1.iteration
WHERE
T1.id = 223652 AND
T2.id IS NULL
Or...
SELECT
T1.iteration AS maxiteration,
T1.column
FROM
Table T1
INNER JOIN (SELECT id, MAX(iteration) AS maxiteration FROM Table T2 GROUP BY id) SQ ON
SQ.id = T1.id AND
SQ.maxiteration = T1.iteration
WHERE
T1.id = 223652
EDIT: I didn't see the ORA error the first time reading the question and it wasn't tagged as Oracle specific. I think that there may be some differences in the syntax and use of aliases in Oracle, so you may need to tweak some of the above queries.
The Oracle error is telling you that it doesn't know what maxiteration is, because the column alias isn't available yet inside the subquery. You need to refer to it by the table alias and column name instead of the column alias I believe.
You do something like
select maxiteration,column from table a join (select max(iteration) as maxiteration from table where id=1) b using (id) where b.maxiteration=a.iteration;
This could of course return multiple rows for one maxiteration unless your table has a constraint against it.