n_station
code_stas nom_station
1 StationA
2 StationB
3 StationC
val_horaire
code_mesure date_val_hor h_01 h_02 h_03
1 14/11/2016 23 29 32
1 15/11/2016 45 47 35
2 14/11/2016 12 15 13
2 15/11/2016 21 23 19
3 14/11/2016 74 75 79
I would like to get the latest (date) row of the table val_horaire and join it with table n_station
Result
cod_stas nom_station date_val_hor h_01 h_02 h_03
1 StationA 15/11/2016 45 47 35
2 StationB 15/11/2016 21 23 19
3 StationC 14/11/2016 74 75 79
How can I achieve this ? The following query does not work
SELECT st.code_stas, st.nom_station, max(vh.date_val_hor), vh.h_01, vh.h_02, vh.h_03
FROM n_station st
INNER JOIN val_horaire vh
ON st.code_stas = vh.code_mesure
GROUP BY st.code_stas, st.nom_station, vh.h_01, vh.h_02, vh.h_03
This will show me multiple times a station
Solution No.1:
SELECT
st.code_stas,
st.nom_station,
MAX(vh.date_val_hor) KEEP(DENSE_RANK FIRST ORDER BY st.nom_station DESC) AS date_val_hor,
MAX(vh.h_01) KEEP(DENSE_RANK FIRST ORDER BY st.nom_station DESC) AS h_01,
MAX(vh.h_02) KEEP(DENSE_RANK FIRST ORDER BY st.nom_station DESC) AS h_02,
MAX(vh.h_03) KEEP(DENSE_RANK FIRST ORDER BY st.nom_station DESC) AS h_03
FROM
n_station st,
val_horaire vh
WHERE
st.code_stas = vh.code_mesure
GROUP BY st.code_stas, st.nom_station
Solution No.2:
SELECT code_stas, nom_station, h_01, h_02, h_03 FROM (
SELECT
st.code_stas,
st.nom_station,
vh.date_val_hor,
vh.h_01,
vh.h_02,
vh.h_03,
ROW_NUMBER() OVER(PARTITION BY st.code_stas, st.nom_station ORDER BY vh.date_val_hor DESC) AS DISTINCT_FLG
FROM
n_station st,
val_horaire vh
WHERE
st.code_stas = vh.code_mesure
)
WHERE DISTINCT_FLG = 1
Something like this (?):
SELECT st.code_stas, st.nom_station, zzz.MAX_date_val_hor, vh.h_01, vh.h_02, vh.h_03
FROM (SELECT code_mesure, MAX(date_val_hor) AS MAX_date_val_hor FROM val_horaire GROUP BY code_mesure) ZZZ
INNER JOIN
n_station st ON st.code_stas=zzz.code_mesure
INNER JOIN val_horaire vh
ON st.code_stas = vh.code_mesure
GROUP BY st.code_stas, st.nom_station, zzz.MAX_date_val_hor, vh.h_01, vh.h_02, vh.h_03;
Related
For this query :
WITH CTE (customerID,FirstWeek,RN) AS
(
SELECT
customerID, MIN(DATEPART(week, tp_date)) TransWeek,
ROW_NUMBER() OVER (PARTITION BY customerID ORDER BY DATEPART(week, tp_date) ASC)
FROM
all_table
GROUP BY
customerID, DATEPART(week, tp_date)
)
SELECT
CTE.customerID, CTE.FirstWeek,
(SELECT TOP 1 (DATEPART(week, c.tp_date))
FROM all_table c
WHERE c.customerID = CTE.customerID
AND DATEPART(week, C.tp_date) > CTE.FirstWeek) SecondWeek
FROM
CTE
WHERE
RN = 1
I get this result :
CustomerID
firstweek
secondweek
C001
35
37
C002
35
37
C003
35
39
C003
36
37
But what to do if I want the result to show only the first week in 35 and second week 37? The result should look like this:
CustomerID
firstweek
secondweek
C001
35
37
C002
35
37
Simply, run a second CTE to apply your filter in final query. Also, you may not need the ROW_NUMBER window function:
WITH agg AS (
SELECT
customerID,
MIN(DATEPART(week, tp_date)) AS FirstWeek
FROM all_table
GROUP BY
customerID
), main AS (
SELECT
customerID,
FirstWeek,
(
SELECT TOP 1 DATEPART(week, c.tp_date)
FROM all_table c
WHERE c.customerID = agg.customerID
AND DATEPART(week, c.tp_date) > agg.FirstWeek
) AS SecondWeek
FROM agg
)
SELECT *
FROM main
WHERE FirstWeek = 35
AND SecondWeek = 37
Let's say I have data like this
CustomerID
Trans_date
C001
01-sep-22
C001
04-sep-22
C001
14-sep-22
C002
03-sep-22
C002
01-sep-22
C002
18-sep-22
C002
20-sep-22
C003
02-sep-22
C003
28-sep-22
C004
08-sep-22
C004
18-sep-22
But I'm unable to find the first and second transaction based on Trans_date.
I wish for the result to look like this:
CustomerID
Trans_week
first
second
C001
35
35
37
C001
35
35
37
C001
37
35
37
C002
35
35
37
C002
35
35
37
C002
37
35
37
C002
38
35
37
C003
35
35
39
C003
39
35
39
C004
36
36
37
C004
37
36
37
And for the last result will show like this:
CustomerID
first
second
C001
35
37
C002
35
37
C003
35
39
C004 didnt include because i would need who cust id who come first in their 1st week.
You may use ROW_NUMBER() function -inside a subquery- to get the first and second transaction dates for a customer, then use conditional MAX window function on the results of that subquery.
SELECT CustomerID, DATEPART(week,CustTrans) AS Trans_week,
DATEPART(week, MAX(CASE rn WHEN 1 THEN CustTrans END) OVER (PARTITION BY CustomerID)) first,
DATEPART(week, MAX(CASE rn WHEN 2 THEN CustTrans END) OVER (PARTITION BY CustomerID)) second
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY CustTrans) rn
FROM trydata
) T
ORDER BY CustomerID, Trans_week
See a demo on SQL Server.
As you requested in the comments, if you want to select only one row per customer that showing the first and second weeks, use the following query:
SELECT CustomerID,
DATEPART(week, MAX(CASE rn WHEN 1 THEN CustTrans END)) first,
DATEPART(week, MAX(CASE rn WHEN 2 THEN CustTrans END)) second
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY CustTrans) rn
FROM trydata
) T
WHERE rn <= 2
GROUP BY CustomerID
ORDER BY CustomerID
See a demo.
with cte (RN,CustomerID, FirstWeek,SecondWeek ) as
( SELECT ROW_NUMBER() over(partition by CustomerID ORDER BY CustomerID ) RN, CustomerID,FirstWeek, isnull((select TOP 1 (DATEPART(week,CustTrans))
from trydata c
where c.CustomerID = SRC.CustomerID AND DATEPART(week,C.CustTrans) > SRC.FirstWeek
ORDER BY DATEPART(week,C.CustTrans) ),'0') AS SecondWeek
FROM (
SELECT CustomerID,DATEPART(week,CustTrans) TransWeek,
(select MIN(DATEPART(week,CustTrans)) from trydata c where c.CustomerID = trydata.CustomerID) AS FirstWeek
FROM trydata
) SRC )
select CustomerID,FirstWeek,SecondWeek from cte where RN = 1
Output:
Example 2 :
WITH CTE (CustomerID,FIrstWeek,RN) AS (
SELECT CustomerID,MIN(DATEPART(week,CustTrans)) TransWeek,
ROW_NUMBER() over(partition by CustomerID ORDER BY DATEPART(week,CustTrans) asc ) FROM TryData
GROUP BY CustomerID,DATEPART(week,CustTrans)
)
SELECT CTE.CustomerID, CTE.FIrstWeek,
(select TOP 1 (DATEPART(week,c.CustTrans))
from trydata c
where c.CustomerID = CTE.CustomerID AND DATEPART(week,C.CustTrans) > CTE.FIrstWeek
) SecondWeek
FROM CTE
WHERE RN = 1
FIddle Demo
Edit: This can be done on easier way and less complex.
I have a table as follows
Date
Id
Group
Name
ScoreCount
2022-06-20
1
Athlete
Adam
52
2022-06-23
1
Athlete
Adam
77
2022-06-25
1
Athlete
Adam
79
2022-06-19
1
Employee
Adam
65
2022-06-22
1
Employee
Adam
28
I'd like this for the dates to be added for each individual id and type of group. So it should look something like:
Date
Id
Group
Name
ScoreCount
2022-06-20
1
Athlete
Adam
52
2022-06-21
1
Athlete
Adam
52
2022-06-22
1
Athlete
Adam
52
2022-06-23
1
Athlete
Adam
77
2022-06-24
1
Athlete
Adam
77
2022-06-25
1
Athlete
Adam
79
2022-06-19
1
Employee
Adam
65
2022-06-20
1
Employee
Adam
65
2022-06-21
1
Employee
Adam
65
2022-06-22
1
Employee
Adam
28
My code is as follows:
WITH t as (SELECT
Id,
Group,
Name,
min(Date) as MinDate
max(Date) as MaxDate
FROM recordTable
GROUP BY Id,Group,Name
SELECT t.Id,
t.Group,
t.Name,
c.Days,
(SELECT LAST_VALUE(ScoreCount) FROM recordTable WHERE t.Id = recordTable.Id AND t.Group = recordTable.Group)
FROM t
LEFT JOIN calendar c ON c.Days BETWEEN t.MinDate AND t.MaxDate
calendar is the table that contains individual dates for the year 2022, so they can be joined. Everything works, except for the ScoreCount, which Last_Value isn't actually doing what I want it to do. How can I fix this?
You can simply try reversing the order of your joined tables -
WITH t as (SELECT Id,
Group,
Name,
min(Date) as MinDate,
max(Date) as MaxDate
FROM recordTable
GROUP BY Id,Group,Name
)
SELECT t.Id,
t.Group,
t.Name,
c.Days,
(SELECT LAST_VALUE(ScoreCount) OVER(<your over clause is missing>)
FROM recordTable
WHERE t.Id = recordTable.Id
AND t.Group = recordTable.Group)
FROM calendar c
LEFT JOIN t ON c.Days BETWEEN t.MinDate AND t.MaxDate
Although I have not tested the query yet this will give you an idea to proceed further.
You don't need the last_value, you can get the first value
WITH t as (
SELECT
[Id],
[Group],
[Name],
min([Date]) as MinDate,
max([Date]) as MaxDate
FROM recordTable
GROUP BY [Id],[Group],[Name]
)
SELECT
t.Id,
t.[Group],
t.[Name],
c.[Date],
(SELECT top 1 ScoreCount
from recordTable x
where x.[Date] <= c.[Days]
and x.[Group] = t.[Group]
and x.[Name] = t.[Name]
order by x.[Date] desc
) ScoreCount
FROM t
LEFT JOIN calendar c ON c.[Days] BETWEEN t.MinDate AND t.MaxDate
base_table
eom account_id closings checkouts
2018-11-01 1 21 147
2018-12-01 1 20 214
calendar_table
month account_id
2020-11-01 1
2014-04-01 1
Based on two tables, above, I would like to create a month-by-month cumulative closings and checkouts.
The calendar_table contains the months the account id is active. Thus, it is used as the main table (in the from clause).
with
base_table as (
select eom, account_id, closings, checkouts
from base_table bt
where account_id in (3,30,122,152,161,179)
)
,calendar_table as (
select ct.month, c.external_id as account_id
from calendar_table ct
left join customers c
on c.id = ct.organization_id
where account_id in (3,30,122,152,161,179)
)
,cumulative_table as (
select ct."month"
,list.account_id
,coalesce(bt.closings,0) as closings
,coalesce(sum(closings) OVER (PARTITION BY list.account_id
ORDER BY ct."month"
rows BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),0)
as cum_closings
,coalesce(bt.checkouts,0) as checkouts
,coalesce(sum(checkouts) OVER (PARTITION BY list.account_id
ORDER BY ct."month"
rows BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),0)
AS cum_checkouts
from calendar_table ct
cross join (select distinct account_id from base_table) list
left join base_table bt
on bt.account_id = list.account_id and bt.eom = ct.month
)
select *
from cumulative_table
The query above returns a cumulative table that contains duplications, probably because of the cross join.
month account_id closings cum_closings checkouts cum_checkouts
01/11/17 1 20 20 282 282
01/11/17 1 20 40 282 564
01/11/17 1 20 60 282 846
01/12/17 1 17 77 346 1192
01/12/17 1 17 94 346 1538
01/12/17 1 17 111 346 1884
I expect the query to return one month per account id.
month account_id closings cum_closings checkouts cum_checkouts
01/11/17 1 20 20 282 282
01/12/17 1 17 37 346 628
You can do more simple :
WITH list AS
( select bt.eom, bt.account_id, bt.closings, bt.checkouts
, ct.month, ct.organization_id
from base_table bt
inner join calendar_table ct
on ct.account_id = bt.account_id
where bt.account_id in (3,30,122,152,161,179)
)
select l.month, c.external_id as account_id
, coalesce(l.closings,0) as closings
, coalesce( sum(l.closings) OVER (PARTITION BY l.account_id
ORDER BY l."month"
rows BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
, 0
) as cum_closings
, coalesce(l.checkouts,0) as checkouts
, coalesce( sum(l.checkouts) OVER (PARTITION BY l.account_id
ORDER BY l."month"
rows BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
, 0
) AS cum_checkouts
from list as l
left join customers c
on c.id = l.organization_id ;
I have a query that return this result. How can i limit the occurrence of a value from the 4th column.
19 1 _BOURC01 1
20 1 _BOURC01 3 2019-11-18
20 1 _BOURC01 3 2017-01-02
21 1 _BOURC01 6
22 1 _BOURC01 10
23 1 _BOURC01 13 2016-06-06
24 1 _BOURC01 21 2016-09-19
My Query:
SELECT "_44_SpeakerSpeech"."id" AS "id", "_44_SpeakerSpeech"."active" AS "active", "_44_SpeakerSpeech"."id_speaker" AS "id_speaker", "_44_SpeakerSpeech"."Speech" AS "Speech", "34 Program Weekend"."date" AS "date"
FROM "_44_SpeakerSpeech"
LEFT JOIN "_34_programWeekend" "34 Program Weekend" ON "_44_SpeakerSpeech"."Speech" = "34 Program Weekend"."theme_id"
WHERE "id_speaker" = "_BOURC01"
ORDER BY id_speaker, Speech, date DESC
Thanks
I think this is what you want here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY s.id, s.active, s.id_speaker, s.Speech
ORDER BY p.date DESC) rn
FROM "_44_SpeakerSpeech" s
LEFT JOIN "_34_programWeekend" p ON s.Speech = p.theme_id
WHERE s.id_speaker = '_BOURC01'
)
SELECT id, active, id_speaker, Speech, date
FROM cte
WHERE rn = 1;
This logic assumes that when two or more records all have the same columns values (excluding the date), you want to retain only the latest record.