Query help, rank function maybe? - sql

rank function? can anybody assist me with this. I'd like my query to only return the lowest date for the P0260 field, and the lowest date for the painting field.
JOB ID LINE ORDER RCVD USE DATE
P0260 61785 1 2400 24 10/26/2012
P0260 63462 3 2400 24 11/14/2012
P0260 66372 1 1 0 2/15/2013
P0260 66371 1 5 0 3/1/2013
PAINTING 12246 1 29 27 11/30/2006
PAINTING 30885 1 160 0 9/29/2009
Painting 30885 2 160 0 9/29/2009
PAINTING 31155 1 25 0 11/6/2009

Ok, without knowing wich RDBMS (and version) you are using, this solution should work on most of them:
SELECT A.*
FROM YourTable A
INNER JOIN (SELECT JOB, MIN([USE DATE]) MinUseDate
FROM YourTable
GROUP BY JOB) B
ON A.JOB = B.JOB AND A.[USE DATE] = B.MinUseDate

SELECT query2.PART_ID, query2.ID, query2.LINE_NO, query2.DEL_SCHED_LINE_NO, query2.SYSADM_PURC_LINE_DEL.ORDER_QTY, query2.RECEIVED_QTY, query2.DESIRED_RECV_DATE, query2.SYSADM_PURC_ORDER_LINE.ORDER_QTY, query2.TOTAL_RECEIVED_QTY, query2.[USE DATE]
FROM query2
INNER JOIN (SELECT query2.PART_ID, MIN(query2.[USE DATE]) MinUseDate
FROM query2
GROUP BY PART_ID) B
ON query2.PART_ID = B.PART_ID AND query2.[USE DATE] = B.MinUseDate;

Related

Counting Consecutive Weeks based on separate numeric column

I'm working on a problem where the employees get a certain score each week. They will only have 1 score each week, being saved each Saturday. I want to count the number of consecutive weeks (working backwards from today) that they are above 50. If the previous week is not above 50 then they would have 0 consecutive weeks. If they've had a score above 50 each week for the past year, then they would have 52 consecutive weeks.
I've tried using the Row_Number() function to get this, but can't figure out how to incorporate the score as a factor in that.
This is an example of the data set:
EmpID Last Week Score
A 7/6/2019 60
A 6/29/2019 84
A 6/22/2019 21
B 7/6/2019 41
B 6/29/2019 92
C 7/6/2019 77
C 6/29/2019 55
C 6/22/2019 71
C 6/15/2019 63
This is what I've tried so far
SELECT
EmpID,
EOW,
SCORE,
ROW_NUMBER() OVER(PARTITION BY EMP ORDER BY EOW DESC) AS RN
FROM a
ORDER BY EmpID, EOW DESC
But that only gives me a row count of each employee. I need the count to stop when their score is below 50 as below:
EmpID Last Week Score RN
A 7/6/2019 60 1
A 6/29/2019 84 2
A 6/22/2019 21 -
B 7/6/2019 41 -
B 6/29/2019 92 -
C 7/6/2019 77 1
C 6/29/2019 55 2
C 6/22/2019 71 3
C 6/15/2019 63 4
I then need to get a single number of the consecutive weeks for each employee so that I can join the results to a larger query that pulls additional info about the employee. The scores are in a different table which is why I have to join it. The query should produce a result like:
EmpID Last Week Consecutive Week
A 7/6/2019 2
B 7/6/2019 0
C 7/6/2019 4
Does this make sense? Any help would be appreciated
I used conditional aggregation and running total.
The basic idea is:
If the number >= 50, the derived column will sum 0.
The consecutive zero(s) will stop at the first <50 value.
Then count the number of zeros.
I added the special case [group D]:
('D','7/6/2019' , 51 )
('D','6/29/2019' , 49)
('D','6/22/2019' ,52 )
There will be one single zero in this case.
If there is only one zero, I think the consecutive weeks should be zero instead of one.
I added [group D] into the test sample.
Try this:
SELECT B.EmpID,B.[Last Week], CASE WHEN B.TOTAL <= 1 THEN 0 ELSE B.TOTAL END AS RN
FROM (
SELECT A.EmpID, MAX(EOW) AS [Last Week], SUM(CASE WHEN A.COUNT1 = 0 THEN 1 ELSE 0 END) AS TOTAL
FROM
(
SELECT EMPID,EOW, Score
, SUM(CASE WHEN SCORE >= 50 THEN 0 ELSE 1 END) OVER (PARTITION BY EMPID ORDER BY EOW DESC) AS COUNT1
FROM TEST
GROUP BY EMPID,EOW,Score
)A
GROUP BY A.EmpID
)B
Test Result:
DB<>Fiddle

Find out per day the first trip duration and last trip duration of a bike

Find out per day first trip duration and last trip duration of a bike.
Table
trip_id bike-id trip_date trip_starttime trip_duration
1 1 2018-12-01 12:00:00.0000000 10
2 2 2018-12-01 14:00:00.0000000 25
3 1 2018-12-01 14:30:00.0000000 5
4 3 2018-12-02 05:00:00.0000000 12
5 3 2018-12-02 19:00:00.0000000 37
6 1 2018-12-02 20:30:00.0000000 20
Expected Result
trip_date bike-id first_trip_duration last_trip_duration
2018-12-01 1 10 5
2018-12-01 2 25 25
2018-12-02 1 20 20
2018-12-02 3 12 37
I tried it with below code,
select A.trip_date,A.[bike-id],A.trip_duration AS Minduration,B.trip_duration AS MaxDUrtaion from
(SELECT T1.trip_date,T1.[bike-id],T1.trip_duration FROM TRIP T1
INNER JOIN (
select trip_date,[bike-id] , min(trip_starttime) AS Mindate
from Trip group by trip_date,[bike-id] ) T2
oN T1.[bike-id]=T2.[bike-id] AND T1.trip_date=T2.trip_date AND t1.trip_starttime=t2.Mindate ) as A
inner join
(SELECT T1.trip_date,T1.[bike-id],T1.trip_duration FROM TRIP T1
INNER JOIN (
select trip_date,[bike-id] , MAX(trip_starttime) AS Maxdate
from Trip group by trip_date,[bike-id] ) T2
oN T1.[bike-id]=T2.[bike-id] AND T1.trip_date=T2.trip_date AND t1.trip_starttime=t2.Maxdate ) as B
ON A.[bike-id]=B.[bike-id] AND A.trip_date=B.trip_date
order by A.trip_date,A.[bike-id]
I want to know some other logic too, please help out.
First, determine for each date/bike the first and last trip.
Then, determine the duration of these trips.
Something like this might do it (I didn't test it though):
SELECT minmax.trip_date,
minmax.bike_id,
first.trip_duration AS first_trip_duration,
last.trip_duration AS last_trip_duration
FROM (SELECT trip_date,
bike_id,
MIN(trip_starttime) AS first_trip,
MAX(trip_starttime) AS last_trip
FROM trip_table
GROUP BY trip_date,
bike_id
) minmax
JOIN trip_table first
ON minmax.trip_date = first.trip_date
AND minmax.bike_id = first.bike_id
AND minmax.first_trip = first.trip_starttime
JOIN trip_table last
ON minmax.trip_date = last.trip_date
AND minmax.bike_id = last.bike_id
AND minmax.last_trip = last.trip_starttime
Supposing you have the necessary indexes on the table.
Preferably a unique index on (bike_id, trip_date, starttime).
select trip_date,bike_id
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime) as first_trip_duration
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime desc) as last_trip_duration
from trip;
Assuming window functions are supported, this can be done with first_value.
select distinct
trip_date
,bike_id
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime) as first_trip_duration
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime desc) as last_trip_duration
from trip

Combining Two Tables & Summing REV amts by Mth

Below are my two tables of data
Acct BillingDate REV
101 01/05/2018 5
101 01/30/2018 4
102 01/15/2018 2
103 01/4/2018 3
103 02/05/2018 2
106 03/06/2018 5
Acct BillingDate Lease_Rev
101 01/15/2018 2
102 01/16/2018 1
103 01/19/2018 2
104 02/05/2018 3
105 04/02/2018 1
Desired Output
Acct Jan Feb Mar Apr
101 11
102 3
103 5 2
104 3
105 1
106 5
My SQL Script is Below:
SELECT [NewSalesHistory].[Region]
,[NewSalesHistory].[Account]
,SUM(case when [NewSalesHistory].[billingdate] between '6/1/2016' and '6/30/2016' then REV else 0 end ) + [X].[Jun-16] AS 'Jun-16'
FROM [NewSalesHistory]
FULL join (SELECT [Account]
,SUM(case when [BWLease].[billingdate] between '6/1/2016' and '6/30/2016' then Lease_REV else 0 end ) as 'Jun-16'
FROM [AirgasPricing].[dbo].[BWLease]
GROUP BY [Account]) X ON [NewSalesHistory].[Account] = [X].[Account]
GROUP BY [NewSalesHistory].[Region]
,[NewSalesHistory].[Account]
,[X].[Jun-16]
I am having trouble combining these tables. If there is a rev amt and lease rev amt then it will combine (sum) for that account. If there is not a lease rev amt (which is the majority of the time), it brings back NULLs for all other rev amts accounts in Table 1. Table one can have duplicate accounts with different Rev, while the Table two is one unique account only w Lease rev. The output above is how I would like to see the data.
What am I missing here? Thanks!
I would suggest union all and group by:
select acct,
sum(case when billingdate >= '2016-01-01' and billingdate < '2016-02-01' then rev end) as rev_201601,
sum(case when billingdate >= '2016-02-01' and billingdate < '2016-03-01' then rev end) as rev_201602,
. . .
from ((select nsh.acct, nsh.billingdate, nsh.rev
from NewSalesHistory
) union all
(select bl.acct, bl.billingdate, bl.rev
from AirgasPricing..BWLease bl
)
) x
group by acct;
Okay, so there are a few things going on here:
1) As Gordon Linoff mentioned you can perform a union all on the two tables. Be sure to limit your column selections and name your columns appropriately:
select
x as consistentname1,
y as consistentname2,
z as consistentname3
from [NewSalesHistory]
union all
select
a as consistentname1,
b as consistentname2,
c as consistentname3
from [BWLease]
2) Your desired result contains a pivoted month column. Generate a column with your desired granularity on the result of the union in step one. F.ex. months:
concat(datepart(yy, Date_),'-',datename(mm,Date_)) as yyyyM
Then perform aggregation using a group by:
select sum(...) as desiredcolumnname
...
group by PK1, PK2, yyyyM
Finally, PIVOT to obtain your result: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
3) If you have other fields/columns that you wish to present then you first need to determine whether they are measures (can be aggregated) or are dimensions. That may be best addressed in a follow up question after you've achieved what you set out for in this part.
Hope it helps
As an aside, it seems like you are preparing data for reporting. Performing these transformations can be facilitated using a GUI such as MS Power Query. As long as your end goal is not data manipulation in the DB itself, you do not need to resort to raw sql.

cross reference nearest date data

I have three table ElecUser, ElecUsage, ElecEmissionFactor
ElecUser:
UserID UserName
1 Main Building
2 Staff Quarter
ElecUsage:
UserID Time Amount
1 1/7/2010 23230
1 8/10/2011 34340
1 8/1/2011 34300
1 2/3/2012 43430
1 4/2/2013 43560
1 3/2/2014 44540
2 3/6/2014 44000
ElecEmissionFactor:
Time CO2Emission
1/1/2010 0.5
1/1/2011 0.55
1/1/2012 0.56
1/1/2013 0.57
And intended outcome:
UserName Time CO2
1 2010 11615
1 2011 37752 (34340*0.55 + 34300*0.55)
1 2012 24320.8
1 2013 24829.2
1 2014 25387.8
2 2014 25080
The logic is ElecUsage.Amount * ElecEmissionFactor.
If same user and same year, add them up for the record of that year.
My query is:
SELECT ElecUser.UserName, Year([ElecUsage].[Time]), SUM((ElecEmissionFactor.CO2Emission*ElecUsage.Amount)) As CO2
FROM ElecEmissionFactor, ElecUser INNER JOIN ElecUsage ON ElecUser.UserID = ElecUsage.UserID
WHERE (((Year([ElecUsage].[Time]))>=Year([ElecEmissionFactor].[Time])))
GROUP BY ElecUser.UserName, Year([ElecUsage].[Time])
HAVING Year([ElecUsage].[Time]) = Max(Year(ElecEmissionFactor.Time));
However, this only shows the year with emission factor.
The challenge is to reference the year without emission factor to the latest year with emission factor.
Sub-query may be one of the solutions but i fail to do so.
I got stuck for a while. Hope to see your reply.
Thanks
Try something like this..
-- not tested
select T1.id, year(T1.time) as Time, sum(T1.amount*T2.co2emission) as CO2
from ElecUsage T1
left outer join ElecEmissionFactor T2 on (year(T1.time) = year(T2.time))
Group by year(T1.time), T1.id
use sub query to get the corresponding factor in this way
select T1.id,
year(T1.time) as Time,
sum(T1.amount*
(
select top 1 CO2Emission from ElecEmissionFactor T2
where year(T2.time) <= year(T1.time) order by T2.time desc
)
) as CO2
from ElecUsage T1
Group by year(T1.time), T1.id

How do I write sql query from this result?

I wasn't sure what could be the title for my question so sorry about that.
I'm trying to write a SQL query to achieve the no. of members who should get reimbursed from a pharmacy.
For example : I went to pharmacy, I took a vaccine but by mistake I paid from my pocket. so now Pharmacy needs to reimburse me that amount. Lets say I have the data like:
MemberId Name ServiceDate PresNumber PersonId ClaimId AdminFee(in $)
1 John 1/1/2011 123 345 456 0
1 John 1/21/2011 123 345 987 20
2 Mike 2/3/2011 234 567 342 0
2 Mike 2/25/2011 234 567 564 30
5 Linda 1/4/2011 432 543 575 0
5 Linda 4/6/2011 987 543 890 0
6 Sonia 2/6/2011 656 095 439 0
This data shows all members from that pharmacy who got reimbursed and who haven't.
I need to find out the member having AdminFee 0 but i also need to check another record for the same member having same PresNumber, same PersonId where the ServiceDate falls within 30 Days of the Original Record.
If another record meets this criteria and the AdminFee field contains a value (is NOT 0) then it means that person has already been reimbursed. So from the data you can see John and Mike have already been reimbursed and Linda and Sonia need to be reimbursed.
Can anybody help me how to write an SQL query on this?
You don't mention what SQL engine you're using, so here is some generic SQL. You'll need to adapt the date math and the return of True/False ( in the second option) to whatever engine you're using:
-- Already reimbursed
SELECT * FROM YourTable YT1 WHERE AdminFee = 0 AND EXISTS
(SELECT * FROM YourTable YT2
WHERE YT2.MemberID = YT1.MemberID AND
YT2.PresNumber = YT1.PresNumber AND
YT2.ServiceDate >= YT1.ServiceDate - 30 AND
AdminFee > 0)
-- Need reimbursement
SELECT * FROM YourTable YT1 WHERE AdminFee = 0 AND NOT EXISTS
(SELECT * FROM YourTable YT2
WHERE YT2.MemberID = YT1.MemberID AND
YT2.PresNumber = YT1.PresNumber AND
YT2.ServiceDate >= YT1.ServiceDate - 30 AND
AdminFee > 0)
or
-- Both in one.
SELECT YT1.*,
CASE WHEN YT2.MemberID IS NULL THEN False ELSE True END AS AlreadyReimbursed
FROM YourTable YT1 JOIN YourTable YT2 ON
YT1.MemberID = YT2.MemberID AND
YT1.PresNumber = YT2.PresNumber AND
YT1.ServiceDate <= YT2.ServiceDate + 30
WHERE YT1.AdminFee = 0 AND YT2.AdminFee > 0)
You need to use datediff function in SQL Server and as parameter to pass day and to join the table above by other alias. I do not have SQL Server but I think it should be like this
Select memberid
from PaymentLog p
inner join PaymentLog d on p.serviceid = d.serviceid
and p.memberid = d.memberid
and p.personid = d.personid
Where adminfee = 0
and datediff(day, p.servicedate, d.servicedate) < 30
I called a table paymentlog