Count with row_number function SQL CTE - sql

I have the below CTEs that work perfectly, but I want to count the "cl.memb_dim_id" by "cl.post_date" but I am not sure how to do that? When adding in the count function I get an error that highlights the ' row number' so I am assuming I cant have both order and group together ????
WITH
DATES AS
(
select to_date('01-jan-2017') as startdate,to_date('02-jan-2017') as enddate
from dual
),
Claims as (select distinct
cl.memb_dim_id,
row_number () over (partition by cl.Claim_number order by cl.post_date desc) as uniquerow,
cl.Claim_number,
cl.post_date,
ct.claim_type,
ap.claim_status_desc,
dc.company_desc,
dff.io_flag_desc,
pr.product_desc,
cl.prov_dim_id,
cl.prov_type_dim_id
from dw.fact_claim cl
inner join dates d
on 1=1
and cl.post_date >= d.startdate
and cl.post_date <= d.enddate
and cl.provider_par_dim_id in ('2')
and cl.processing_status_dim_id = '1'
and cl.company_dim_id in ('581','585','586','589','590','591','588','592','594','601','602','603','606','596','598','597','579','599','578','577','573','574','576','575')
left join dw.DIM_CLAIM_STATUS ap
on cl.claim_status_dim_id = ap.claim_status_dim_id
left join dw.dim_claim_type ct
on cl.claim_type_dim_id = ct.claim_type_dim_id
and cl.claim_type_dim_id in ('1','2','6','7')
left join dw.DIM_COMPANY dc
on cl.company_dim_id = dc.company_dim_id
left join dw.DIM_IO_FLAG dff
on cl.io_flag_dim_id = dff.io_flag_dim_id
left join dw.dim_product pr
on cl.product_dim_id = pr.product_dim_id
)
Select * from claims where uniquerow ='1'

First, does this work?
count(cl.memb_dim_id) over (partition by cl.Claim_number, cl.post_date) as cnt,
Second, it is strange to be using analytic functions with select distinct.

Related

Nesting queries on JOINS and top1 with ties

I am trying to use the result of the below SQL query-1 such that I can make another JOIN on this with my second query result to retrieve Fundsrc on the common ID - Project.
QUERY 1-
SELECT top 1 with ties
t.project, r.rel_value AS "FundSrc" ,r.date_to
from atsproject t
LEFT OUTER JOIN aglrelvalue r ON(t.client=r.client AND r.rel_attr_id='ZB18' AND r.attribute_id='B0' AND t.project=r.att_value)
WHERE r.date_To > '04/30/2020' and status='n'
ORDER BY row_number() over (partition by t.project order by t.project, r.rel_value)
I cannot put the JOIN inside the above query as it will mess with the result. Instead, if I can do a nesting on this then I think that should solve the issue.
My second query is -
SELECT
t.project,t.work_order as activity, r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1 ON( t.work_order = r1.dim_value AND t.client = r1.client AND r1.attribute_id = 'BF')
WHERE t.client='PC' and t.status = 'N'
The Output should be -
t.project,t.work_order from query 2 + Fundsrc from Query 1, with the common id on Project ID.
Any suggestions on this is highly appreciated.
You can wrap 'subqueries' in parenthesis and then join them.
Can you try this?:
SELECT *
FROM (
SELECT top 1 with ties t.project,
r.rel_value AS "FundSrc",
r.date_to
FROM atsproject t
LEFT OUTER JOIN aglrelvalue r
ON t.client=r.client
AND r.rel_attr_id='ZB18'
AND r.attribute_id='B0'
AND t.project=r.att_value
WHERE r.date_To > '04/30/2020' and status='n'
ORDER BY row_number() over (partition by t.project order by t.project, r.rel_value)
) AS TABLE_1
LEFT JOIN
(
SELECT t.project,
t.work_order as activity,
r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1
ON t.work_order = r1.dim_value
AND t.client = r1.client
AND r1.attribute_id = 'BF'
WHERE t.client='PC' and t.status = 'N'
) AS TABLE_2
ON TABLE_1.PROJECT = TABLE2.PROJECT
I am pretty sure an ORDER BY clause will not work within a subquery. Thus, this should probably work:
SELECT *
FROM (
SELECT t.project,
r.rel_value AS "FundSrc",
r.date_to,
row_number() over (partition by t.project order by t.project, r.rel_value) AS MY_RANKING
FROM atsproject t
LEFT OUTER JOIN aglrelvalue r
ON t.client=r.client
AND r.rel_attr_id='ZB18'
AND r.attribute_id='B0'
AND t.project=r.att_value
WHERE r.date_To > '04/30/2020' and status='n'
) AS TABLE_1
LEFT JOIN
(
SELECT t.project,
t.work_order as activity,
r1.labor_funding_source2_fx AS "Designated Labour Funding"
FROM atsworkorder t
LEFT OUTER JOIN afxactlaborfund r1
ON t.work_order = r1.dim_value
AND t.client = r1.client
AND r1.attribute_id = 'BF'
WHERE t.client='PC' and t.status = 'N'
) AS TABLE_2
ON TABLE_1.PROJECT = TABLE2.PROJECT
WHERE TABLE_1.MY_RANKING = 1
Note: On your formatting, wrap words within ` when they refer to code. They will look like this.
Wrap blocks of code within three of those (three at the beginning and at the end). It will look like the blocks of code above.

Select all records between two dates but one record on same day depending on plate

I have select query :
select
f.FirmaID,f.FirmaAdi,t.BelgeID,t.BelgeTuru,t.Tarih,t2.Plaka,t2.SasiNo,t4.AracMarka,t4.AracTip,case when x.Miktar=1 then 4 else x.miktar end as LastikAdet,
t3.CariKodu,t3.CariAdi,t3.CariGsm1,t3.CariGsm2,t3.CariTel1,t3.CariTel2,t3.CariAdres
from alsatr t WITH (NOLOCK)
left join Firma f WITH (NOLOCK) on f.FirmaID = t.AlsatrFirmaID
left join AracBilgi t2 WITH (NOLOCK) on t2.AracBilgiUID = t.AsAracBilgiUID and t2.AracBilgiID= t.AracBilgi
left join Cari t3 WITH (NOLOCK) on t.AsCariUID= t3.CariUID
left join Araclar t4 WITH (NOLOCK) on t4.AracID= t2.AB_AracID
outer apply
(select COUNT(1) soktak,Miktar FROM alsatD d WITH (NOLOCK)
where
d.AlsatDUID = t.AlsatrUID and d.AsStokKodu='LA-0001' group by Miktar) x
where
isnull(t3.FiloID,0) > 0
and t.Tarih between '04.30.2020' and '04.31.2020'
and t.BelgeTuru=55
and x.soktak > 0
and f.FirmaID not in (1,2,103,106,109,114)
order by t.Tarih desc, f.FirmaID desc, t.BelgeID desc
So I want to select all records between two days but I want to select one,latest record (maybe depends on last BelgeID ) on same day with same plate (plaka).
Enclose your query inside a CTE and use ROW_NUMBER() window function:
WITH cte AS (
<your query here>
)
SELECT
t.FirmaID, t.FirmaAdi, t.BelgeID, t.BelgeTuru, t.Tarih, t.Plaka, t.SasiNo, t.AracMarka,
t.AracTip, t.LastikAdet, t.CariKodu, t.CariAdi, t.CariGsm1, t.CariGsm2, t.CariTel1,
t.CariTel2, t.CariAdres
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Tarih, Plaka ORDER BY BelgeID DESC) rn
FROM cte
) t
WHERE t.rn = 1

SQL Join SELECT MAX, But also where a value does not exist

I have the following SQL which works - It displays all of the items, along with the MAX starttime.
However, I'd also like to show items that to not have a record in playlistlog - How would one
SELECT items.idx, items.title, items.artist, playlistlog.starttime
FROM items
LEFT JOIN playlistlog ON playlistlog.item = items.idx
WHERE playlistlog.starttime = (
SELECT MAX(starttime)
FROM playlistlog AS pl2
WHERE pl2.item = items.idx
)
The where clause is turning your left join into an inner join.
Use AND instead of WHERE.
SELECT items.idx, items.title, items.artist, playlistlog.starttime
FROM items
LEFT JOIN playlistlog ON playlistlog.item = items.idx
and playlistlog.starttime = (
SELECT MAX(starttime)
FROM playlistlog AS pl2
WHERE pl2.item = items.idx
)
This can be done a bit shorter using standard SQL's window function:
SELECT items.idx, items.title, items.artist, pl.starttime
FROM items
LEFT JOIN (
select item,
starttime,
row_number() over (partition by item order by starttime desc) as rn
from playlistlog
) pl ON pl.item = items.idx AND pl.rn = 1

Limiting result sets by future date - SQL

The Query below produces a record for each Entry in the SP_ScheduleEvent Table.
SELECT m.MaterialId, m.MaterialTitle, se.EventDateTime, c.ChannelName
FROM GB_Material m
LEFT OUTER JOIN SP_ScheduleEvent se on se.MaterialName = m.MaterialName
INNER JOIN SP_Schedule s on s.ScheduleID = se.ScheduleID
INNER JOIN GB_Channel c on c.ChannelID = s.ChannelID
WHERE LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%'
I want to limit the result set by the nearest future EventDateTime.
So per material name i would like to see one EventDateTime, which should be the nearest future date to the current time.
And lastly, a record may not exist in the SP_ScheduleEvent table for a particular materialname, in which case there should be null returned for the EventDateTime column
SQLFiddle
How would i go about doing this?
First, your LEFT JOIN is immaterial, because the subsequent joins make it an INNER JOIN. Either use LEFT JOIN throughout the FROM statement or switch to INNER JOIN.
I think you can use ROW_NUMBER():
SELECT t.*
FROM (SELECT m.MaterialId, m.MaterialName, m.MaterialTitle, se.EventDateTime,
ROW_NUMBER() over (PARTITION BY m.MaterialId OVER se.EventDateTime DESC) as seqnum
FROM GB_Material m INNER JOIN
SP_ScheduleEvent se
on se.MaterialName = m.MaterialName INNER JOIN
SP_Schedule s
on s.ScheduleID = se.ScheduleID INNER JOIN
GB_Channel c
on c.ChannelID = s.ChannelID
WHERE se.EventDateTime > getdate() AND
(LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%')
) t
WHERE seqnum = 1
ORDER BY se.EventDateTime;
Use the ROW_NUMBER() function:
WITH cte AS (
SELECT m.MaterialId, m.MaterialTitle, se.EventDateTime, c.ChannelName,
ROW_NUMBER() OVER (PARTITION BY m.MaterialId ORDER BY EventDateTime ASC) AS rn
FROM GB_Material m
LEFT OUTER JOIN SP_ScheduleEvent se on se.MaterialName = m.MaterialName
LEFT OUTER JOIN SP_Schedule s on s.ScheduleID = se.ScheduleID
LEFT OUTER JOIN GB_Channel c on c.ChannelID = s.ChannelID
WHERE LOWER(m.MaterialName) like '%foo%' OR LOWER(m.MaterialTitle) like '%foo%'
AND se.EventDateTime > GETDATE()
)
SELECT * FROM cte
WHERE rn=1

how to join a table on a subquery that uses order by and limit

For each row from table tClass matching a given where clause,
join on the first row in tEv, sorted by time, where tEv.class_id = tClass.class_id
The following code throws the error
ORA-01799: a column may not be outer-joined to a subquery
select
c.class_id,
c.class_name,
e.start_time,
e.ev_id
from
tClass c
left join tEv e on (
e.ev_id = (
select
ss1.ev_id
from (
select
ed.ev_id
from
tEvDisp ed,
tEv e
where
ed.class_id = c.class_id
and ed.viewable = 'Y'
and ed.display_until > localtimestamp
and e.ev_id = ed.ev_id
order by
e.start_time
) ss1
where
rownum = 1
)
)
where
c.is_matching = 'Y';
How can this be rewritten to do what is described?
The above is for oracle, but needs to work in sqlite (substituting where necessary)
No idea about SQLite - that would need to be a separate question if this doesn't work - but for Oracle you could do something like this:
select c.class_id,
c.class_name,
e.start_time,
e.ev_id
from tClass c
left join (
select class_id, ev_id, start_time
from (
select ed.class_id,
ed.ev_id,
e.start_time,
row_number() over (partition by ed.class_id order by e.start_time) as rn
from tEvDisp ed
join tEv e on e.ev_id = ed.ev_id
where ed.viewable = 'Y'
and ed.display_until > localtimestamp
)
where rn = 1
) e on e.class_id = c.class_id
where c.is_matching = 'Y';
This uses a subquery which finds the most tEv data, using an analytic row_number() to identify the latest data for each class_id, which is restricted by the rn = 1 filter.
That subquery, consisting of at most one row per class_id, is then used the left outer join against tClass.
This sort of construct should get you what you need. You can fix the details.
select c.classid
, c.classname
, temp.maxstarttime
from tClass c left join (
select c.classid id
max(e.start_time) maxstarttime
from tClass join tEv on tEv.classId = tClass.ClassId
where whatever
group by c.classid) temp on c.classid = temp.id