Select unique field values with condition - sql

I`m new at SQL and my problem is:
I have a table like
card shop time date
1 1 0000 20171001
2 2 0125 20171002
2 1 0344 20171002
3 3 0342 20171103
4 5 1334 20171104
4 4 1225 20171105
5 4 1452 20171106
I need to select two fields (card(card must be unique) and shop) by the minimum value of the columns time and date (date is in priority).
The result should look like this:
card shop time date
1 1 0000 20171001
2 2 0125 20171002
3 3 0342 20171103
4 5 1334 20171104
5 4 1452 20171106
Thank you in advance!

For SQL Server you could use WITH TIES
select top 1 with ties *
from yourTable
order by row_number() over (partition by card order by date asc, time asc)

you can use sub-query and aggregate function
select * from yourtable t
where t.date in (select min(date) from yourtable t1
where t.card=t1.card )

Related

Get earliest value from a column with other aggregated columns in postgresql

I have a very simple stock ledger dataset.
1. date_and_time store_id product_id batch opening_qty closing_qty inward_qty outward_qty
2. 01-10-2021 14:20:00 56 a 1 5 1 0 4
3. 01-10-2021 04:20:00 56 a 1 8 5 0 3
4. 02-10-2021 15:30:00 56 a 1 9 2 1 8
5. 03-10-2021 08:40:00 56 a 2 2 6 4 0
6. 04-10-2021 06:50:00 56 a 2 8 4 0 4
Output I want:
select date, store_id,product_id, batch, first(opening_qty),last(closing_qty), sum(inward_qty),sum(outward_qty)
e.g.
1. date store_id product_id batch opening_qty closing_qty inward_qty outward_qty
2. 01-10-2021 56 a 1 8 1 0 7
I am writing a query using First_value window function and tried several others but not able to get the out put I want.
select
date,store_id,product_id,batch,
FIRST_VALUE(opening_total_qty)
OVER(
partition by date,store_id,product_id,batch
ORDER BY created_at
) as opening__qty,
sum(inward_qty) as inward_qty,sum(outward_qty) as outward_qty
from table
group by 1,2,3,4,opening_total_qty
Help please.
As your expected result is one row per group of rows with the same date, you need aggregates rather than window functions which provide as many rows as the ones filtered by the WHERE clause. You can try this :
SELECT date_trunc('day', date),store_id,product_id,batch
, (array_agg(opening_qty ORDER BY datetime ASC))[1] as opening__qty
, (array_agg(closing_qty ORDER BY datetime DESC))[1] as closing_qty
, sum(inward_qty) as inward_qty
, sum(outward_qty ) as outward_qty
FROM table
GROUP BY 1,2,3,4
see the test result in dbfidle.

Get most frequent value from a windowing function

I have a SQL table that looks like:
user_id role date
1 1 2019-11-26 21:20:54.397+00
1 2 2019-11-27 22:46:28.923+00
2 1 2019-12-06 22:17:53.925+00
2 3 2019-12-13 00:12:28.006+00
3 1 2019-11-25 21:57:17.701+00
3 1 2019-12-06 20:48:28.314+00
3 1 2019-12-15 23:59:06.81+00
4 3 2019-12-04 15:26:10.639+00
4 3 2019-11-22 19:20:01.025+00
4 3 2019-11-25 12:38:53.169+00
I would like to get the most frequent role according to past dates and use. The result should looks like:
user_id role date most_frequent_role
1 1 2019-11-26 21:20:54.397+00 NULL
1 2 2019-11-27 22:46:28.923+00 1
2 1 2019-12-06 22:17:53.925+00 NULL
2 3 2019-12-13 00:12:28.006+00 1
3 1 2019-11-25 21:57:17.701+00 NULL
3 1 2019-12-06 20:48:28.314+00 1
3 1 2019-12-15 23:59:06.81+00 1
4 3 2019-12-04 15:26:10.639+00 NULL
4 3 2019-11-22 19:20:01.025+00 3
4 3 2019-11-25 12:38:53.169+00 3
Following query will work for you.
select test.user_id,test.role,test.role_date,
case when test.role_date in
(select min(role_date) from test group by user_id) then NULL
else t.role end as MOST_FREQUENT_ROLE
from
(select user_id,min(role) as role from test group by user_id
)t
join test on t.user_id=test.user_id
order by user_id,role_date
Output
USER_ID ROLE ROLE_DATE MOST_FREQUENT_ROLE
1 1 26-NOV-19 -
1 2 27-NOV-19 1
2 1 06-DEC-19 -
2 3 13-DEC-19 1
3 1 25-NOV-19 -
3 1 06-DEC-19 1
3 1 15-DEC-19 1
4 3 22-NOV-19 -
4 3 25-NOV-19 3
4 3 04-DEC-19 3
If you strictly want to go with window function, Try below -
SELECT user_id
,role
,date
,CASE WHEN date = MIN(date) OVER(PARTITION BY user_id ORDER BY date)
THEN NULL
ELSE MIN(role) OVER(PARTITION BY user_id) END MOST_FREQUENT_ROLE
FROM YOUR_TABLE;
Technically, what you are trying to calculate is the mode (this is a statistical term).
Postgres has a built-in mode() function. Alas, it does not work as you need as a window function, so it provides little help.
I would recommend using a lateral join:
select t.*, m.role
from t left join lateral
(select t2.role
from t t2
where t2.user_id = t.user_id and
t2.date < t.date
group by t2.role
order by count(*) desc,
max(date) desc -- in the event of ties, use the most recent
limit 1
) m
on 1=1
order by user_id, date;
Here is a db<>fiddle. Note that I added some rows to give an example of where the running mode changes.
This will not be particularly efficient but an index on (user_id, date, role) should help.
If you have just a handful of roles there are probably more efficient solutions. If that is the case and performance is an issue, ask a new question.

How to get minimum date by group id per client id

I am trying to Select Group ID, and minimum dates per clients ID.
This is sample data set.
ClientID GroupID DataDate
1 9 2016-05-01
2 8 2015-04-01
3 7 2016-07-05
1 6 2015-01-05
1 5 2014-11-12
2 4 2016-11-02
1 3 2013-02-14
2 2 2011-04-01
I wrote
SELECT
clientID, MIN(DataDate)
FROM sampleTable
GROUP BY clientID
But in this query, I do not have GroupID selected. I need to include GroupID to join another table.
If I do:
Select
ClientID, GroupID, MIN(DataDate)
FROM sampleTable
GROUP BY ClientID, GroupID
It won't really get minimum dates per client.
Could you help me. How I should do this?
You can use ROW_NUMBER instead:
SELECT
ClientID, GroupID, DataDate
FROM (
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY ClientID ORDER BY DataDate)
FROM SampleData
) t
WHERE rn = 1
If you want to include ties, use RANK instead of ROW_NUMBER.
I hope i understood your question correctly .
You want to display min dates for each client id's
If my table has data like this:
CID GID D1
1 9 03-06-2016
1 6 01-06-2017
1 5 01-06-2015
1 3 01-06-2014
2 4 01-06-2017
2 8 01-06-2014
3 5 03-06-2016
2 4 01-06-2011
Output :
CID GID D1
1 3 01-06-2014
2 4 01-06-2011
3 5 03-06-2016
This is what i think you can go with .
select cx.cid,cx.gid, cx.d1 from cli cx where cx.d1=(select min(c1.d1) from cli c1 where c1.cid=cx.cid)
group by cx.cid,cx.gid,cx.d1
order by cx.gid
Hope it helps.

Simple data, Complex query on SQL Server

I need to make a query over an SQL Server table but I don't know exactly how.
Consider this table (the real table is much more complex, Ord1 and Ord2 are dates that could be null, but i simplified it to this case):
Data of MyTable
ID MaqID Ord1 Ord2
------------------------
1 144 4 3
2 144 2 1
3 12 2 3
4 144 3 5
5 12 3 1
6 144 4 2
7 12 2 4
8 144 2 3
9 12 1 5
10 12 3 2
I need records for specific MaqID in Specific Order. I get that with this Query:
SELECT * FROM myTable WHERE MaqID=144 ORDER BY MaqID, Order1 DESC, Order2
Wich give me:
ID MaqID Ord1 Ord2
------------------------
6 144 4 2
1 144 4 3
4 144 3 5
2 144 2 1
8 144 2 3
Now, I need a single query that, for each MaqID, return the first ID for each subquery following above order. The result should be:
Expected result
MaqID ID
-----------
144 6
12 5
I have already try distinct conbination of TOP a MAX, but TOP result only one result and i need one for each MaqID, and for Max I have not field to maximize.
To sumarize: I need the first ID for each MaqID from a subquery in a specific order
Any ideas? Thanks!
You can do this using row_number():
select t.*
from (select t.*,
row_number() over (partition by macid Order1 DESC, Order2) as seqnum
from mytable t
) t
where seqnum = 1;

How to do grouping by a date span?

Conside this Table Structure.
Key ID VISITDATE
1 1 2011-01-07
2 1 2011-01-09
3 2 2011-01-10
4 1 2011-01-12
5 3 2011-01-12
6 1 2011-01-15
7 2 2011-01-21
9 1 2011-02-28
10 2 2011-03-21
11 1 2011-01-06
I need to get all the IDs,Key,min(VisitDate) where VisitDate is within 10 days span?if you have two visits within 10 days one row need to be there in the result.
Result
KEY ID VISITDATE
11 1 2011-01-06
3 2 2011-01-10
5 3 2011-01-12
7 2 2011-01-21
9 1 2011-02-28
10 2 2011-03-21
Can this be done without a self join. i have a query which does a self join with the table on ID and check the datediff.is there a better solution?can we use recursive CTE here?
EDIT
Prefer a solution which can use the index on date column
Yes a CTE would work nicely for this (everything with me is CTEs lately)...
;WITH TenDayVisits
AS (
SELECT
ID
,MIN(VisitDate) AS VisitDate
FROM Visits
GROUP BY ID
UNION ALL
SELECT
t.ID
,v.VisitDate
FROM Visits AS v
JOIN TenDayVisits AS t ON v.ID = t.ID
AND DATEDIFF(dd,t.Visitdate,v.VisitDate) > 10
)
SELECT
DISTINCT
v.[key]
,t.id
,t.VisitDate
FROM TenDayVisits as T
JOIN Visits AS v ON t.id = v.id
AND t.VisitDate = v.VisitDate