SQL QUERY TO SHOW FIRST IN AND FIRST OUT - sql

my query like this :
select u.name, (case when IOType=0 then format(Edatetime,'hh:mm tt') end) as 'IN' ,
(case when IOType=1 then format(Edatetime,'hh:mm tt') end) as 'out'
from TestZEOTRA T
inner join Mx_UserMst U on t.UsrRefCode=u.UserID
where UsrRefCode='1506' and CAST(Edatetime as date)='28 OCT 2019'
output getting :
BUT I NEED TO SHOW THE RESULT LIKE THIS

Assuming that your in and outs are interleaved, you can use row_number() and aggregation:
select ram, min(in) as in, min(out) as out
from (select t.*,
row_number() over (partition by name, out order by in) as seqnum_in,
row_number() over (partition by name, in order by in) as seqnum_out
from t
) t
group by (case when in is null then seqnum_out else seqnum_in);
For your particular query, this is a little simpler:
select u.name,
min(case when IOType = 0 then format(t.Edatetime, 'hh:mm tt') end) as in_time
max(case when IOType = 1 then format(t.Edatetime, 'hh:mm tt') end) as out_time
from Mx_UserMst U join
(select t.*,
row_number() over (partition by t.userrefcode, t.iotype order by t.edatetime) as seqnum
from TestZEOTRA T
where UsrRefCode = '1506' and
cast(t.Edatetime as date) = '2019-10-28'
) t
on t.UsrRefCode = u.UserID
group by u.UserID, u.name, seqnum

Related

expected result is not getting

I have a data like this:
And I want this - I am trying with PIVOT but not getting the expected results:
Query is
SELECT AttendeeID,[Quantity1],[PROD1],[Quantity2],[PROD2],[Quantity3],[PROD3] FROM
(SELECT * ,
row_number() over(partition by AttendeeID order by AttendeeID)rn
from #ProductTestingwithPosition2) TT
PIVOT
(MAX(product) for ProductPosition in ([PROD1],[PROD2],[PROD3])) AS Tab2
PIVOT
(sum(Quantity) for QuantityPosition in ([Quantity1],[Quantity2],[Quantity3])) AS Tab3
I am getting this output:
Just use conditional aggregation:
SELECT AttendeeID,
MAX(CASE WHEN ProductPosition = 'PROD1' THEN product END) as prod1,
MAX(CASE WHEN QuantityPosition = 'QUANTITY1' THEN quantity END) as quantity1,
MAX(CASE WHEN ProductPosition = 'PROD2' THEN product END) as prod2,
MAX(CASE WHEN QuantityPosition = 'QUANTITY2' THEN quantity END) as quantity2,
MAX(CASE WHEN ProductPosition = 'PROD3' THEN product END) as prod3,
MAX(CASE WHEN QuantityPosition = 'QUANTITY3' THEN quantity END) as quantity3
FROM (SELECT ptp.* ,
row_number() over (partition by AttendeeID, ProductPosition order by AttendeeID) as seqnum
FROM #ProductTestingwithPosition2 ptp
) ptp
GROUP BY AttendeeID, seqnum;
PIVOT -- in addition to being non-standard -- is very finicky. Conditional aggregation is much more powerful and less prone to errors.

SQL joining most recent event by criteria to missing value

I have a SQL table that records interactions and the changes that happen in an interaction by interactionkey, user, group, and skill. I want to find the duration of each of the actions (A,B,C) by the grouping variables. Whenever action C happens, the skillKey is left blank (not NULL) and I need it to take the value of the last Skill in that interaction by the user and group so it is grouped together. The first table is the raw SQL data for 1 interaction, and the second is how I need it to look. Edit: I'm using Microsoft SQL Server Management Studio.
Here's what I have so far but it doesn't account for the last skill the user used in the group and interactionkey so it remains blank and adds it up seperately
SELECT
[InteractionKey],
[User],
[StartTime],
[SkillKey],
[GroupKey],
SUM(CASE WHEN ActionKey = 'A' THEN ActionDuration ELSE 0 END) AS 'ActionADuration',
SUM(CASE WHEN ActionKey = 'B' THEN ActionDuration ELSE 0 END) AS 'ActionBDuration',
SUM(CASE WHEN ActionKey = 'C' THEN ActionDuration ELSE 0 END) AS 'ActionCDuration'
FROM
(SELECT
[ActionKey],
[InteractionKey],
[SkillKey],
[GroupKey],
SUM(ActionDuration) AS 'ActionDuration',
[User],
CAST(StartTime AS DATE)
FROM
[InteractionTable]
GROUP BY
InteractionKey, User, SkillKey, GroupKey, ActionKey,
CAST(StartTime AS DATE)) sub
GROUP BY
InteractionKey, User, Date, SkillKey, GroupKey
ORDER BY
InteractionKey
Raw SQL Server table:
Desired output:
All you need is to prepare another "table" with SkillKey already filled as you need, and then use this table in your query.
I will use CTE in my code,
and it is different for divverent versions of SQL Server.
The first one is preferable, but it's for servers starting with 2012.
If you are on lower version use the second query.
-- for ##version >= 2012
with cte as
(
select *,
case
when SkillKey <> ''
then SkillKey
else lag(SkillKey) over(partition by InteractionKey, [User], GroupKey order by [Date])
end as SkillKey
from InteractionTable
)
SELECT
[InteractionKey],
[User],
[StartTime],
[SkillKey],
[GroupKey],
SUM(CASE WHEN ActionKey = 'A' THEN ActionDuration ELSE 0 END) AS 'ActionADuration',
SUM(CASE WHEN ActionKey = 'B' THEN ActionDuration ELSE 0 END) AS 'ActionBDuration',
SUM(CASE WHEN ActionKey = 'C' THEN ActionDuration ELSE 0 END) AS 'ActionCDuration'
FROM
(SELECT
[ActionKey],
[InteractionKey],
[SkillKey],
[GroupKey],
SUM(ActionDuration) AS 'ActionDuration',
[User],
CAST(StartTime AS DATE)
FROM
cte
GROUP BY
InteractionKey, User, SkillKey, GroupKey, ActionKey,
CAST(StartTime AS DATE)) sub
GROUP BY
InteractionKey, User, Date, SkillKey, GroupKey
ORDER BY
InteractionKey
The second:
-- for ##version >= 2005
with r as
(
select *,
row_number() over(partition by InteractionKey, [User], GroupKey order by [Date]) as rn
from InteractionTable
)
,cte as
(
select r1.*,
case
when r1.SkillKey <> ''
then r1.SkillKey
else r2.SkillKey
end as SkillKey
from r r1
left join r r2
on r1.rn = r2.rn + 1
)
SELECT
[InteractionKey],
[User],
[StartTime],
[SkillKey],
[GroupKey],
SUM(CASE WHEN ActionKey = 'A' THEN ActionDuration ELSE 0 END) AS 'ActionADuration',
SUM(CASE WHEN ActionKey = 'B' THEN ActionDuration ELSE 0 END) AS 'ActionBDuration',
SUM(CASE WHEN ActionKey = 'C' THEN ActionDuration ELSE 0 END) AS 'ActionCDuration'
FROM
(SELECT
[ActionKey],
[InteractionKey],
[SkillKey],
[GroupKey],
SUM(ActionDuration) AS 'ActionDuration',
[User],
CAST(StartTime AS DATE)
FROM
cte
GROUP BY
InteractionKey, User, SkillKey, GroupKey, ActionKey,
CAST(StartTime AS DATE)) sub
GROUP BY
InteractionKey, User, Date, SkillKey, GroupKey
ORDER BY
InteractionKey

Window Functions

I want to add a window functions.
Take the min date when visit = Y and end as Associd.
TableA
ID Date AssocId Visit
1 1/1/17 10101 Y
1 1/2/17 10102 Y
End Results.
ID Date AssocId
1 1/1/17 10101
SQL > This gives me the min date but I need the AssocId associated to that date.
SELECT MIN(CASE WHEN A.VISIT = 'Y'
THEN A.DATE END) OVER (PARTITION BY ID)
AS MIN_DT,
You can use FIRST_VALUE():
SELECT MIN(CASE WHEN A.VISIT = 'Y' THEN A.DATE END) OVER (PARTITION BY ID) AS MIN_DT,
FIRST_VALUE(CASE WHEN A.VISIT = 'Y' THEN A.ASSOCID END) KEEP (DENSE_RANK FIRST OVER (PARTITION BY ID ORDER BY A.VISIT DESC, A.DATE ASC),
Note that this is a little tricky with conditional operations. I would be more inclined to use a subquery to nest the query operations. The outer expression would be:
SELECT MAX(CASE WHEN Date = MIN_DT THEN ASSOCID END) OVER (PARTITION BY ID)
If you wanted this per ID, I would suggest:
select id, min(date),
first_value(associd) over (partition by id order by date)
from t
where visit = 'Y'
group by id;
That is, use aggregation functions.
You seems want :
select t.*
from table t
where visit = 'Y' and
date= (select min(t1.date) from table t1 where t1.id = t.id);

Aggregation disables window function capability

I am trying to re-write the query where I am joining the query on itself:
select count(distinct case when cancelled_client_id is null and year(RUM.first_date) = year(date) and RUM.first_date <= .date then user_id
when cancelled_client_id is null and year(coalesce(RUM.first_date,RUR.first_date)) = year(date)
and coalesce(RUM.first_date,RUR.first_date) <= RUL.date then user_id end) as
from RUL
left join
(
select enrolled_client_id, min(date) as first_date
from RUL
where enrolled_client_id is not null
group by enrolled_client_id
) RUR on RUR.enrolled_client_id=RUL.enrolled_client_id
left join
(
select managed_client_id, min(date) as first_date
from RUL
where managed_client_id is not null
group by managed_client_id
) RUM on RUM.managed_client_id=RUL.managed_client_id
Using window functions:
count(distinct case when cancelled_client_id is null
and year(min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id)) = year(date)
and min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id) <= date
then user_id
when cancelled_client_id_rev is null
and year(coalesce(
min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id),
min(case when managed_client_id is not null then date end) over(partition by managed_client_id))) = year(date)
and coalesce(
min(case when enrolled_client_id is not null then date end) over(partition by enrolled_client_id),
min(case when managed_client_id is not null then date end) over(partition by managed_client_id)) <= date
then user_id end)
from RUL
However I am getting an error that "Windowed functions cannot be used in the context of another windowed function or aggregate" due to the count(distinct min). Any work-arounds?
I have no idea what the count(distinct) is supposed to be doing, but you can simplify the code to:
select count(distinct case when cancelled_client_id is null and
year(rum_first_date) = year(date) and
rum_first_date <= rul.date
then user_id
when cancelled_client_id is null and
year(coalesce(RUM_first_date, RUR_first_date)) = year(rul.date) and
coalesce(rum_first_date, rur_first_date) <= RUL.date
then user_id
end) as . . .
from (select RUL.*,
min(date) over (partition by enrolled_client_id) as rur_date,
min(date) over (partition by managed_client_id) as rum_date
from RUL
) RUL

Return the First, Second and Third Earliest Purchase Dates per Purchaser

for a list of purchaser email addresses, I am trying to return one line per purchaser that has the columns '1stOrderDate', '2ndOrderDate', '3rdOrderDate' and 'TotalNumberofOrders'
I have tried using the ROW_Number function in the WHERE clause of subqueries but it reports that Windowed functions aren't allowed in the WHERE clause, so any help on how I fill in the ???s below would be gratefully received!
SELECT
PT.email AS 'Email',
MIN(OT.orderdate) AS '1stOrderDate',
??? AS '2ndOrderDate',
??? AS '3rdOrderDate',
COUNT(DISTINCT OT.order_reference) AS 'TotalNumberOfOrders'
FROM dbo.Orders AS OT
JOIN dbo.Purchaser AS PT ON OT.account_reference = PT.account_reference
GROUP BY PT.Email
You can do this with row_number() and conditional aggregation:
SELECT PT.email,
MAX(CASE WHEN seqnum = 1 THEN OT.OrderDate END) as OrderDate_1,
MAX(CASE WHEN seqnum = 2 THEN OT.OrderDate END) as OrderDate_2,
MAX(CASE WHEN seqnum = 3 THEN OT.OrderDate END) as OrderDate_3,
COUNT(DISTINCT OT.order_reference) AS TotalNumberOfOrders
FROM (SELECT o.*, ROW_NUMBER() OVER (PARTITION BY account_reference ORDER BY o.orderdate) as seqnum
FROM dbo.Orders o
) OT JOIN
dbo.Purchaser PT
ON OT.account_reference = PT.account_reference
GROUP BY PT.Email
A couple of notes:
Don't use single quotes for column aliases. Instead, choose column names that do not require escaping.
For the segnum = 1 logic, you can use MIN(), but I think consistency is a benefit here.
EDIT:
My guess is that the problem is the difference between a account_reference and email. Try this:
SELECT email,
MAX(CASE WHEN seqnum = 1 THEN OT.OrderDate END) as OrderDate_1,
MAX(CASE WHEN seqnum = 2 THEN OT.OrderDate END) as OrderDate_2,
MAX(CASE WHEN seqnum = 3 THEN OT.OrderDate END) as OrderDate_3,
COUNT(DISTINCT OT.order_reference) AS TotalNumberOfOrders
FROM (SELECT o.*, ROW_NUMBER() OVER (PARTITION BY pt.email ORDER BY o.orderdate) as seqnum
FROM dbo.Orders o JOIN
dbo.Purchaser PT
ON OT.account_reference = PT.account_reference
) OT
GROUP BY PT.Email