Inline Views with JOIN ON syntax possible? - sql

I have two inline views that I can join via the classic join method. Results are as expected.
However, trying to adapt to JOIN ON syntax, I cannot see how. Restriction? WITH required? Or need to create two separate views and then apply - I presume will work. Cannot find anything in this regard.
The view is as follows, trying to get a match between BUY and SELL.
select BUY.*, SELL.* from (
select Z.*, 'LONG' from (
select X.commodity, X.market_place, X.max_qty, Y.maturity_dt, rank() over
(partition by X.commodity, X.market_place order by y.maturity_dt ASC) as
rank_val
from
(select commodity, market_place, max(qty) as max_qty
from OPEN_POSITIONS
where prod_type = 'future'
and qty > 0
group by commodity, market_place
) X,
open_positions Y
where Y.qty = X.max_qty
and Y.commodity = X.commodity
and Y.prod_type = 'future'
and Y.market_place = X.market_place ) Z
where Z.rank_val = 1 ) BUY,
(
select Z.*, 'SHORT' from (
select X.commodity, X.market_place, X.min_qty, Y.maturity_dt, rank() over
(partition by X.commodity, X.market_place order by y.maturity_dt ASC) as
rank_val
from
(select commodity, market_place, min(qty) as min_qty
from OPEN_POSITIONS
where prod_type = 'future'
and qty < 0
group by commodity, market_place
) X,
open_positions Y
where Y.qty = X.min_qty
and Y.commodity = X.commodity
and Y.prod_type = 'future'
and Y.market_place = X.market_place ) Z
where Z.rank_val = 1) SELL
where BUY.commodity = SELL.commodity
and BUY.market_place = SELL.market_place

You can try something like below based on the database.
;With AllData AS
(
select commodity, market_place, qty
from OPEN_POSITIONS
where prod_type = 'future'
),
X AS
(
SELECT
commodity, market_place, max(qty) as max_qty
FROM AllData
WHERE qty > 0
group by commodity, market_place
),
Z AS
(
SELECT
X.commodity, X.market_place, X.max_qty, Y.maturity_dt, rank() over
(partition by X.commodity, X.market_place order by y.maturity_dt ASC) as rank_val
FROM AllData Y INNER JOIN X ON Y.qty = X.max_qty AND Y.commodity = X.commodity AND Y.market_place = X.market_place
),
BUY AS
(
SELECT
commodity, market_place, max_qty, maturity_dt,rank_val
FROM Z
WHERE rank_val = 1
),
A AS
(
SELECT
commodity, market_place, max(qty) as max_qty
FROM AllData
WHERE qty < 0
group by commodity, market_place
),
B AS
(
SELECT
A.commodity, A.market_place, A.max_qty, Y.maturity_dt, rank() over
(partition by A.commodity, A.market_place order by y.maturity_dt ASC) as rank_val
FROM AllData Y INNER JOIN A ON Y.qty = A.max_qty AND Y.commodity = A.commodity AND Y.market_place = A.market_place
),
SELL AS
(
SELECT
commodity, market_place, max_qty, maturity_dt,rank_val
FROM B
WHERE rank_val = 1
)
SELECT
bu.*;sl.*
FROM BUY bu INNER JOIN SELL AS sl ON bu.commodity = sl.commodity
and bu.market_place = sl.market_place

Not possible, need to make a view first

Related

Sql Server 2008 table join

I have written one query in SQL. I can't get correct output.
here I have attached screenshot.
This is query Output
but I want it like this
You don't need the union subquery (unless you need to remove duplicates). This should do what you want:
select max(case when status = 'O' then ref end) as O,
max(case when status = 'E' then ref end) as E,
max(case when status = 'A' then ref end) as A
from (select p.*, row_number() over (partition by status order by status) as seqnum
from nl_pmnt
where status in ('O', 'E', 'A')
) p
group by seqnum
Try this:
select [O],[E],[A] from (
select row_number() over (order by (select null)) [RN], ref [O] from nl_pmnt where [status] = 'O' and ref <> ''
) [O] left join (
select row_number() over (order by (select null)) [RN], ref [E] from nl_pmnt where [status] = 'O' and ref <> ''
) [E] on [O].[RN] = [E].[RN] left join (
select row_number() over (order by (select null)) [RN], ref [A] from nl_pmnt where [status] = 'O' and ref <> ''
) [A] on [O].[RN] = [A].[RN]
You can use PIVOT
SELECT [O],[E],[A] FROM (
select ROW_NUMBER() OVER( PARTITION BY status ORDER BY (SELECT NULL)) RN, ref, status from nl_pmnt
where ref <> '') SRC
PIVOT(MAX(ref) FOR status IN ([O],[E],[A])) PVT

Get next row if coloumn has same value

Good day, I'm trying to select a data. Please check my query and table first.
I have this query
select * from
(
SELECT * from
(
select distinct TOP 201233 row, b.OutletCode as 'Kode Otlet',
i.Description as 'Area',
c.Nilai,a.Nip, b.Fullname 'Nama Lengkap', f.positioncode as 'Posisi Sebelumnya',
case when a.[status]=0
then j.ApprovedDate else p.ApprovedDate
end as 'Tanggal Upgrade/Demosi Sebelumnya',
d.positioncode as 'Posisi Baru', a.tanggal as 'Tanggal Upgrade/Demosi'
from penilaian_header a
left join Employee b on a.Nip = b.Nip
left join Position f on b.PositionCode = f.PositionCode
left join Position d on a.PositionCode = d.PositionCode
left join arealeader g on g.OutletCode = b.OutletCode
left join outlet h on g.OutletCode = h.OutletCode
left join area i on i.areacode = h.areacode
left join cutoff k on a.periode = k.cutoffcode
left join
(select ROW_NUMBER() OVER(PARTITION BY KodePenilaianH ORDER BY idPenilaiand ASC) AS Row,
Nilai,KodePenilaianH from penilaian_Detail ) c on a.KodePenilaian = c.KodePenilaianH
left join
( SELECT ROW_NUMBER() OVER (PARTITION BY nip ORDER BY ApprovedDate desc) AS rownumber,
ApprovedDate, Nip FROM historyposition ) AS p on a.nip=p.nip and p.rownumber = 2
left join ( SELECT ROW_NUMBER() OVER (PARTITION BY nip ORDER BY ApprovedDate desc) AS rownumber, ApprovedDate, Nip
FROM historyposition ) AS j on a.nip=j.nip and j.rownumber = 1
where a.flag = 1 and h.AreaCode like '%%'
and Periode like '%CO-2016-9-16-15%' and a.nip = '1004863'
--and tanggal <= k.[to] and tanggal >= k.[from]
order by i.Description asc) nilai pivot ( sum(nilai) for row in ([1],[2],[3],[4],[5]) ) piv)A order by Area;
with above query i get this result
and i have this table HistoryPosition
KodeMutasiP OldPosition NewPosition ApprovedBy ApprovedDate Nip KodePenilaian
HP0000514 P007 P007 0802678 2016-09-15 1004863 PE0000787
HP0000513 P007 P007 0802678 2016-04-04 1004863 PE0000130
NULL NULL P007 NULL 2016-04-04 1004863 NULL
NULL NULL P041 NULL 2016-01-20 1004863 NULL
NULL NULL P007 NULL 2015-02-12 1004863 NULL
ok. So what i want to do is set Posisi Sebelumnya and Tanggal Upgrade/Demosi Sebelumnya in the first picture with newposition and Approveddate from the second picture.
But with this condition
if newposition and nip col in the second picture same with the second row then jump to the second, if the second same with the third then jump to the fourth, if the fourth different with the third then choose the third.
I have write the query to choose it here is my query
select * INTO #tMP from historyposition where nip = '1004863' order by approveddate desc
declare #NewPosition varchar(50), #NewPositionLast varchar(50), #ApproveDate datetime, #ApproveDateLast datetime
select top 1 #NewPositionLast = NewPosition, #ApproveDateLast=ApprovedDate from #tmp
WHILE EXISTS (SELECT * FROM #tMP)
BEGIN
select top 1 #NewPosition = NewPosition, #ApproveDate=ApprovedDate from #tmp
if (#NewPosition = #NewPositionLast)
begin
set #NewPositionLast = #NewPosition
set #ApproveDateLast = #ApproveDate
end
else
begin
break
end
delete top(1) #tMP
END
select #NewPositionLast , #ApproveDateLast
drop table #tMP
and i get this result
| P007 | 2016-04-04 00:00:00.000 |
the result is like what i expected.
so my question how to set the Posisi Sebelumnya and Tanggal Upgrade/Demosi Sebelumnya with the result of my last query.
Sorry for my bad english.
here it's my expected result .
I know it's same with the the first picture. But its not right. that because in my first query i choose the second row.
select * from
(
SELECT * from
(
select distinct TOP 201233 row, b.OutletCode as 'Kode Otlet', i.Description as 'Area',
c.Nilai,a.Nip, b.Fullname 'Nama Lengkap',
case when
l.ShortDesc IS NULL then f.ShortDesc else l.ShortDesc
end
as 'PosisiSebelumnya',
-----
z.approveddate,
------
d.ShortDesc as 'Posisi Baru', a.tanggal as 'Tanggal Upgrade/Demosi'
from penilaian_header a
left join Employee b on a.Nip = b.Nip
left join Position f on b.PositionCode = f.PositionCode
left join Position d on a.PositionCode = d.PositionCode
left join position l on a.posisisaatini = l.positioncode
left join arealeader g on g.OutletCode = b.OutletCode
left join outlet h on g.OutletCode = h.OutletCode
left join area i on i.areacode = h.areacode
left join cutoff k on a.periode = k.cutoffcode
left join
(select ROW_NUMBER() OVER(PARTITION BY KodePenilaianH ORDER BY idPenilaiand ASC) AS Row,
Nilai,KodePenilaianH from penilaian_Detail ) c on a.KodePenilaian = c.KodePenilaianH
left join (
select top(1) Nip,NewPosition, ApprovedDate
from (
select Nip,NewPosition,ApprovedDate
, grp = row_number() over(order by ApprovedDate desc) - row_number() over(partition by NewPosition order by ApprovedDate desc)
from HistoryPosition
) t
where grp = 0
order by ApprovedDate
)z on z.Nip = a.Nip
where a.flag = 1
and h.AreaCode like '%%'
and Periode like '%CO-2016-9-16-15%'
and tanggal <= k.[to] and tanggal >= k.[from] order by i.Description asc) nilai
pivot ( sum(nilai) for row in ([1],[2],[3],[4],[5]) ) piv)A order by Area;
i get this.
Your last script retrievs the row with the minimum ApprovedDate. It should be effectively the same as
SELECT ApprovedDate, NewPosition
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY NewPosition ORDER BY ApprovedDate asc) AS rownumber, ApprovedDate, NewPosition
FROM historyposition
WHERE nip = '1004863') t
WHERE rownumber = 1
Try to use this snippet in your bigger query.
EDIT
Detect first group of NewPosition when historyposition is odered by ApprovedDate desc and take first row witn min ApprovedDate in group.
with HistoryPosition as(
-- sample data
select sKodeMutasiP,OldPosition,NewPosition,ApprovedBy
,cast(ApprovedDate as DATE) ApprovedDate, Nip,KodePenilaian
from (
values
('HP0000514','P007','P007',0802678,'2016-09-15',1004863,'PE0000787')
,('HP0000513','P007','P007',0802678,'2016-04-04',1004863,'PE0000130')
,(NULL,NULL,'P007',NULL,'2016-04-04',1004863,NULL)
,(NULL,NULL,'P041',NULL,'2016-01-20',1004863,NULL)
,(NULL,NULL,'P007',NULL,'2015-02-12',1004863,NULL)
) t (sKodeMutasiP,OldPosition,NewPosition,ApprovedBy,ApprovedDate,Nip,KodePenilaian)
)
select top(1) NewPosition, ApprovedDate
from (
select NewPosition,ApprovedDate
, grp = row_number() over(order by ApprovedDate desc) - row_number() over(partition by NewPosition order by ApprovedDate desc)
from HistoryPosition
where nip = 1004863
) t
where grp = 0
order by ApprovedDate;
EDIT2
Use this snippet in OUTER APPLY instead of LEFT JOIN as it depends on other table data:
...
outer apply(
select top(1) NewPosition, ApprovedDate
from (
select NewPosition,ApprovedDate
, grp = row_number() over(order by ApprovedDate desc) - row_number() over(partition by NewPosition order by ApprovedDate desc)
from HistoryPosition hp
where hp.nip = a.nip -- other table
) t
where grp = 0
order by ApprovedDate
) npa
...
If your question is, how can I combine two result sets so that they appear in a single row, the following select can be used:
-- first select
select 1 one, 2 two, 3 three, 0 joinCondition
-- second select
select 'a' a, 'b' b, 'c' c, 0 joinCondition
-- combined
select one, two, three, a, b, c
from (select 1 one, 2 two, 3 three, 0 joinCondition) first
inner join (select 'a' a, 'b' b, 'c' c, 0 joinCondition) second
on first.joinCondition = second.joinCondition
The idea is, we add a dummy column to both selects with equal value so that it can be used to join them

how to show only Y status on my query

I want to show only one status in a field:
select *, ROW_NUMBER() OVER(PARTITION BY t.Docentry ORDER BY t.linealog) FILA
from (select docnum, docentry,Confirmed as confirmado,UserSign2 as usuario,ObjType as tipodoc ,UpdateDate,UpdateTS as Hora,LogInstanc as linealog
from adoc
where ObjType=17
union all
select DocNum, DocEntry,Confirmed,UserSign2,ObjType,UpdateDate,UpdateTS,99 from ordr
) as t
order by DocEntry, FILA
this give me this output:
You can see ndoc in this case 1: give me 4 rows, i just want 2,only Y, I did it with this:
with mycte as (
select *, ROW_NUMBER() OVER(PARTITION BY t.Docentry ORDER BY t.linealog) FILA
from (select docnum, docentry,Confirmed as confirmado,UserSign2 as usuario,ObjType as tipodoc ,docdate,UpdateDate,UpdateTS as Hora,LogInstanc as linealog
from adoc
where ObjType=17
union all
select DocNum, DocEntry,Confirmed,UserSign2,ObjType,docdate,UpdateDate,UpdateTS,99 from ordr
) as t
),
mycte2 as (
select m.*, coalesce(m2.confirmado,'N') confirmadoanterior from mycte m left join mycte m2 on m.fila+1=m2.fila and m.fila=1 )
select * from mycte2 where confirmado='Y' and confirmadoanterior='N'
order by docnum
I just want the line with status ' Y' coming from status 'N' In this case only the row 10.
This is the expected result:
expected result
what kind i do to filter Y status too?
thanks.
Try filter for [Confirmed] = 'Y' inside the UNION ALL query. e.g.
SELECT
*
FROM (
SELECT
*
, ROW_NUMBER() OVER (PARTITION BY t.Docentry ORDER BY t.linealog) FILA
FROM (
SELECT
docnum
, docentry
, Confirmed AS confirmado
, UserSign2 AS usuario
, ObjType AS tipodoc
, docdate
, UpdateDate
, UpdateTS AS Hora
, LogInstanc AS linealog
FROM adoc
WHERE ObjType = 17 AND Confirmed = 'Y' --<< HERE
UNION ALL
SELECT
DocNum
, DocEntry
, Confirmed
, UserSign2
, ObjType
, docdate
, UpdateDate
, UpdateTS
, 99
FROM ordr
WHERE Confirmed = 'Y' --<< & HERE
) AS u
) AS d
ORDER BY
docnum
If this isn't what you are looking for could you please provide "sample data" and "expected result".

Minimum of the maximum values

Consider the below results
Datetime1 DateTime2 Customer
2013-06-19 2011-03-30 IP003779
2014-04-24 2011-03-30 IP003779
2011-03-30 2009-03-18 IP003779
i need to select the minimum of the first column out of the maximums of the second column.
-> 2013-06-19
I'm having a hard time figuring out the query, combining min and max. any thoughts?
Something like this ought to do, I think, to find the min of the max for each customer:
select Customer = t.Customer ,
DateTime2_Max = t.dt2Max ,
DateTime1_Min = min( x.DateTime1 )
from ( select Customer = Customer ,
dt2Max = max( DateTime2 )
from some_table
group by Customer
) t
join some_table x on x.Customer = t.Customer
and x.DateTime2 = t.dt2Max
group by t.Customer ,
t.dt2Max
If you want to look at the table overall, then it gets simpler:
select DateTime2_Max = t.dt2Max ,
DateTime1_Min = min( x.DateTime1 )
from ( select dt2Max = max( DateTime2 )
from some_table
) t
join some_table x on x.DateTime2 = t.dt2Max
group by t.dt2Max
You could also use windowing functions. Broken out by customer, it looks something like:
select *
from ( select * ,
rank = row_number() over (
partition by Customer
order by DateTime2 desc ,
DateTime1 asc
)
) t
where t.rank = 1
order by 1,2,3
And again, simpler if you look at the table as a whole:
select top 1 *
from ( select * ,
rank = row_number() over (
order by DateTime2 desc ,
DateTime1 asc
)
) t
where t.rank = 1
I think this is what you want:
select top 1 *
from table t
order by DateTime2 desc, DateTime1 asc;
Edit:
If you need to do this for all customers, use row_number():
select t.*
from (select t.*,
row_number() over (partition by customer order by datetime2 desc, datetime1 asc) as seqnum
from table t
) t
where seqnum = 1;

is there an easier way than doing UNION ALL?

I have a rather large query which select data from a certain date range.
I would like to group data based on year.
Right now I have:
;with mappingTable as
(
select b.CLIENT_ID,f.patient_id,f.received_date,f.SPECIMEN_ID
from F_ACCESSION_DAILY f
join
(
select f.client_id,a.patient_id
from
(
SELECT
max(received_date) AS received_date
, patient_id AS Patient_ID
FROM F_ACCESSION_DAILY
group by PATIENT_ID
) a
join F_ACCESSION_DAILY f
on f.PATIENT_ID=a.Patient_ID
and f.RECEIVED_DATE=a.received_date
) b
on b.Patient_ID=f.PATIENT_ID
where f.RECEIVED_DATE between '20100101' and '20110101' - as you can see this data is only for 2010
) ---there's much more to this query
as you can see this data is only for 2010
but i would like to do union all for all years: 2008, 2009, 2010, 2011, 2012...
how do i do this without rewriting the query 5 times and doing a union all between all of them?
here's the entire monster query:
;with mappingTable as
(
select b.CLIENT_ID,f.patient_id,f.received_date,f.SPECIMEN_ID
from F_ACCESSION_DAILY f
join
(
select f.client_id,a.patient_id
from
(
SELECT
max(received_date) AS received_date
, patient_id AS Patient_ID
FROM F_ACCESSION_DAILY
group by PATIENT_ID
) a
join F_ACCESSION_DAILY f
on f.PATIENT_ID=a.Patient_ID
and f.RECEIVED_DATE=a.received_date
) b
on b.Patient_ID=f.PATIENT_ID
where f.RECEIVED_DATE between '20100101' and '20110101'
)
,
counted as(
SELECT
PATIENT_ID,
client_id,
--case when COUNT(*)>=12 then 12 else COUNT(*) end TimesTested,
COUNT(*) as timestested,
case when count(*)>1 then
(datediff(day,MIN(received_date),max(received_date)))
/(COUNT(*)-1)
else
0
end as testfreq
FROM mappingTable
GROUP BY
client_id,
patient_id
),counted2 as (
SELECT
client_id,
TimesTested,
CAST(COUNT(*) AS varchar(30)) AS count,
CAST(AVG(testfreq) as varchar(30)) as TestFreq,
CAST(STDEV(TestFreq) as varchar(30)) Stdv
FROM counted
GROUP BY
client_id,
TimesTested
),
counted3 as
(
SELECT
patient_id,
client_id,
TimesTested,
CAST(COUNT(*) AS varchar(30)) AS count,
AVG(testfreq) as TestFreq
FROM counted
GROUP BY
client_id,
TimesTested,
PATIENT_ID
)
,
CountOver12 as
( select client_id,count(*) count
from counted
where timestested>12
group by CLIENT_ID)
,
TotalAvgTestFreq as (
select client_id, SUM(testfreq) / count(testfreq) TotalAvgTestFreq
from counted3
group by client_id
)
,
unpivoted AS (
SELECT
client_id,
ColumnName + CAST(TimesTested AS varchar(10)) AS ColumnName,
ColumnValue
FROM counted2
UNPIVOT (
ColumnValue FOR ColumnName IN (count, TestFreq,stdv)
) u
),
pivoted AS (
SELECT
client_id clientid,
count1, TestFreq1,stdv1,
count2, TestFreq2,stdv2,
count3, TestFreq3,stdv3,
count4, TestFreq4,stdv4,
count5, TestFreq5,stdv5,
count6, TestFreq6,stdv6,
count7, TestFreq7,stdv7,
count8, TestFreq8,stdv8,
count9, TestFreq9,stdv9,
count10, TestFreq10,stdv10,
count11, TestFreq11,stdv11,
count12, TestFreq12,stdv12
FROM unpivoted
PIVOT (
MAX(ColumnValue) FOR ColumnName IN (
count1,TestFreq1,stdv1,
count2,TestFreq2,stdv2,
count3,TestFreq3,stdv3,
count4,TestFreq4,stdv4,
count5,TestFreq5,stdv5,
count6,TestFreq6,stdv6,
count7,TestFreq7,stdv7,
count8, TestFreq8, stdv8,
count9, TestFreq9, stdv9,
count10, TestFreq10,stdv10,
count11, TestFreq11,stdv11,
count12, TestFreq12,stdv12
)
) p
)
,
PatientStats as
(
select
distinct
f.client_id
,datediff(MM,c.mlis_date_established,GETDATE()) MonthsCustomer
,count(distinct patient_id) TotalPatients
,count(distinct specimen_id) TotalSpecimens
from mappingTable f
left join D_CLIENT c
on f.CLIENT_ID=c.CLIENT_ID
group by f.client_id,c.mlis_date_established
)
,
Over12
as
(
select client_id,SUM(c) sumcount from
(
select CLIENT_ID,COUNT(*) c
from mappingTable
group by CLIENT_ID,PATIENT_ID
having count(*)>12
) a
group by client_id
),
GetMedian as(
select client_id, avg(timestested) median_testfreq
from
(
select client_id,
timestested,
rn=row_number() over (partition by CLIENT_ID
order by timestested),
c=count(timestested) over (partition by CLIENT_ID)
from counted3
where timestested>1
) g
where rn in (round(c/2,0),c/2+1)
group by client_id
)
, final as (
SELECT p.*,pivoted.*,c12.count [Count13+],Over12.sumcount SumofGreaterThan12,t.TotalAvgTestFreq,median.median_testfreq
FROM pivoted
left join PatientStats p
on p.CLIENT_ID=pivoted.CLIENTID
left join Over12
on over12.CLIENT_ID=p.CLIENT_ID
left join TotalAvgTestFreq t
on t.CLIENT_ID=p.CLIENT_ID
left join CountOver12 C12
on c12.CLIENT_ID=p.CLIENT_ID
left join GetMedian median
on median.CLIENT_ID=p.CLIENT_ID
where p.CLIENT_ID not in (select CLIENTid from SalesDWH..TestPractices)
)
/* Get the data into a temp table */
SELECT * INTO #TempTable
FROM final
/* Drop the cloumns that are not needed */
ALTER TABLE #TempTable
DROP COLUMN clientid
/* Get results and drop temp table */
SELECT * FROM #TempTable
DROP TABLE #TempTable
Create a table function:
CREATE FUNCTION fn_get_data_by_date_range
(
#start AS VARCHAR(8),
#end AS VARCHAR(8)
)
RETURNS TABLE
AS
RETURN
(
...your query...
WHERE f.RECEIVED_DATE BETWEEN #start AND #end
)
then you can UNION different call of that function:
SELECT * FROM fn_get_data_by_date_range('20100101','20110101')
UNION ALL
SELECT * FROM fn_get_data_by_date_range('20090101','20100101')
UNION ALL
....
UNION ALL
SELECT * FROM fn_get_data_by_date_range('20070101','20080101')