MS SQL Server 2005 GROUP BY and SUM - sql

Hey all, i am trying to create a report to show how much is spent per HRCode. This is my SQL Query so far:
SELECT *
FROM tblWO as WO,
tblWOD as WOD,
tblWA as WA
WHERE WOD.OrderID = WO.ID
AND WA.HRCode = WO.AdministratorCode
AND WO.OrderDate BETWEEN '2010-01-01' AND '2010-08-31'
AND Approved = '1'
ORDER BY WO.OrderDate
I'm trying to fingure out a way that mash all the same HRCode's together and then SUM() each... But my brain is not working today so i need some help :o)
Here is what the database data looks like:
ID Total OrderDate Approved HRCode AdministratorCode OrderID
3272 25.00 2010-01-04 10:48:57.617 1 RN RN 3272
4621 25.00 2010-02-04 11:15:01.600 1 RN RN 4621
4899 50.00 2010-02-04 11:55:01.630 1 02 02 4899
4905 15.00 2010-05-04 11:55:01.190 1 NR NR 4905
5001 50.00 2010-06-04 04:11:55.295 1 RN RN 5001
Any help would be great! Thanks!
SOLVED
SELECT SUM(Total) as Total, AdministratorCode
FROM tblWO as WO,
tblWOD as WOD
WHERE WOD.OrderID = WO.ID
AND WO.OrderDate BETWEEN '2010-01-01' AND '2010-08-31'
AND Approved = '1'
ORDER BY WO.AdministratorCode
David

Remove the OrderDate and ID columns from your select statement:
SELECT SUM(Total) as Total, HRCode
FROM tblWO as WO,
tblWOD as WOD,
tblWA as WA
WHERE WOD.OrderID = WO.ID
AND WA.HRCode = WO.AdministratorCode
AND WO.OrderDate BETWEEN '2010-01-01' AND '2010-08-31'
AND Approved = '1'
GROUP BY HRCode

Related

How can I get distinct data from one col

I need to get member personal data for all our members whose subscriptions have lapsed i.e. have a subscription end date before 31/03/2020, however I want to show one member record only (distinct by membership number) ideally the most recent one
I've tried a ROW_NUMBER() solution SQL - Distinct One Col, Select Multiple other? and a cross apply solution sql distinct, getting 2 columns but I can't get it to work.
SELECT membershipnumber AS Id,
subscription.enddate
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
Output is
Id Enddate
1 2006-04-01 00:00:00.000
1 2001-04-01 00:00:00.000
1 1999-04-01 00:00:00.000
1 1998-04-01 00:00:00.000
1 2008-04-01 00:00:00.000
1 2007-04-01 00:00:00.000
1 2011-04-01 00:00:00.000
1 2005-04-01 00:00:00.000
1 2000-04-01 00:00:00.000
1 1997-04-01 00:00:00.000
2 1999-04-01 00:00:00.000
2 2012-04-01 00:00:00.000
2 2004-04-01 00:00:00.000
2 2001-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
2 2009-04-01 00:00:00.000
2 2005-04-01 00:00:00.000
2 1997-04-01 00:00:00.000
Desired output
Id Enddate
1 2011-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
Solved sql answer
;WITH cte
AS (SELECT membershipnumber AS Id,
subscription.enddate,
Row_number()
OVER (
partition BY membershipnumber
ORDER BY subscription.enddate DESC) AS rownumber
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
)
SELECT *
FROM cte
WHERE rownumber = 1
https://stackoverflow.com/a/6841644/5859743
Not sure if I got your question right.
but you can use DISTINCT in the SELECT, that would show only one record for each member.
SELECT DISTINCT Membershipnumber as Id
,'P' as PartyType
,'A' as Status
,case
when Name = 'Standard Membership paid annually.' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = '3 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands)' and EndDate > '2020-03-31' then 'Overseas member'
when Name = '1 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands).' and EndDate > '2020-03-31' then 'Overseas member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lifetime membership' then 'Lifetime member'
when Name = 'Retired membership paid annually' and EndDate > '2020-03-31' then 'Retired member'
else 'Non member'
end As MemberType
,Title as NamePrefix
,FirstName as FirstName
,Surname as LastName
,DateOfBirth as BirthDate
,'Home' as AddressPurpose
,'Default' as CommunicationReasons
,AddressLine1
,AddressLine2
,AddressLine3
,Addressline4 as CityName
,'' as CountrySubEntityName
,Country as CountryCode
,'' as CountryName
,Postcode as PostalCode
,EmailAddress as Email
FROM [dbo].[UserProfile]
inner join dbo.Subscription on
UserProfile.Id = Subscription.UserProfileId
inner join dbo.SubscriptionType on
SubscriptionType.id = Subscription.SubscriptionTypeId```
If you are getting as above mentioned output. Then from that, your desired output will easily get using distinct.
; with cte as (
----- query which gives you above mentioned output
)
select distinct id, max(Enddate) as Enddate from cte
I suspect you want something like this:
select *
from (select . . ., -- all the columns you want
row_number() over (partition by Membershipnumber as Id order by s.Enddate) as seqnum
from [dbo].[UserProfile] up inner join
dbo.Subscription s
on up.Id = s.UserProfileId inner join
dbo.SubscriptionType st
on st.id = s.SubscriptionTypeId
) x
where seqnum = 1;

T-SQL calculate the percent increase or decrease between the earliest and latest for each project

I have a table like below, I am trying to run a query in T-SQL to get the earliest and latest costs for each project_id according to the date column and calculate the percent cost increase or decrease and return the data-set show in the second table (I have simplified the table in this question).
project_id date cost
-------------------------------
123 7/1/17 5000
123 8/1/17 6000
123 9/1/17 7000
123 10/1/17 8000
123 11/1/17 9000
456 7/1/17 10000
456 8/1/17 9000
456 9/1/17 8000
876 1/1/17 8000
876 6/1/17 5000
876 8/1/17 10000
876 11/1/17 8000
Result:
(Edit: Fixed the result)
project_id "cost incr/decr pct"
------------------------------------------------
123 80% which is (9000-5000)/5000
456 -20%
876 0%
Whatever query I run I get duplicates.
This is what I tried:
select distinct
p1.Proj_ID, p1.date, p2.[cost], p3.cost,
(nullif(p2.cost, 0) / nullif(p1.cost, 0)) * 100 as 'OVER UNDER'
from
[PROJECT] p1
inner join
(select
[Proj_ID], [cost], min([date]) min_date
from
[PROJECT]
group by
[Proj_ID], [cost]) p2 on p1.Proj_ID = p2.Proj_ID
inner join
(select
[Proj_ID], [cost], max([date]) max_date
from
[PROJECT]
group by
[Proj_ID], [cost]) p3 on p1.Proj_ID = p3.Proj_ID
where
p1.date in (p2.min_date, p3.max_date)
Unfortunately, SQL Server does not have a first_value() aggregation function. It does have an analytic function, though. So, you can do:
select distinct project_id,
first_value(cost) over (partition by project_id order by date asc) as first_cost,
first_value(cost) over (partition by project_id order by date desc) as last_cost,
(first_value(cost) over (partition by project_id order by date desc) /
first_value(cost) over (partition by project_id order by date asc)
) - 1 as ratio
from project;
If cost is an integer, you may need to convert to a representation with decimal places.
You can use row_number and OUTER APPLY over top 1 ... prior to SQL 2012
select
min_.projectid,
latest_.cost - min_.cost [Calculation]
from
(select
row_number() over (partition by projectid order by date) rn
,projectid
,cost
from projectable) min_ -- get the first dates per project
outer apply (
select
top 1
cost
from projectable
where
projectid = min_.projectid -- get the latest cost for each project
order by date desc
) latest_
where min_.rn = 1
This might perform a little better
;with costs as (
select *,
ROW_NUMBER() over (PARTITION BY project_id ORDER BY date) mincost,
ROW_NUMBER() over (PARTITION BY project_id ORDER BY date desc) maxcost
from table1
)
select project_id,
min(case when mincost = 1 then cost end) as cost1,
max(case when maxcost = 1 then cost end) as cost2,
(max(case when maxcost = 1 then cost end) - min(case when mincost = 1 then cost end)) * 100 / min(case when mincost = 1 then cost end) as [OVER UNDER]
from costs a
group by project_id

Get last two entries of each account in table

I've got script that gives me all transactions for day for all accounts and sub accounts. His return you can see on the image. What I want, is return result as two last transactions for each accountId and subaccountId. Ideal return would be:
AccountId| SubAccountId| AmountInDay | Date
---------------------------------------------
210 | 1 | 0.00 |2017-06-20 00:00:00.000
210 | 1 | 0.00 |2017-06-05 00:00:00.000
1234 | 1 | 0.00 |2017-06-20 00:00:00.000
1234 | 1 | 0.00 |2017-06-05 00:00:00.000
This is the code of my script:
with CTE1 as
(
select top 2 AccountId, SubAccountId, [Date], sum(Amount_Amount) as Amount
from dbo.PayoutInstallment
group by accountId, SubAccountId, [Date]
)
, CTE2 as
(
select AccountId,SubAccountId, Amount_Amount, [Date],
dense_rank() over (partition by AccountId order by [Date] desc) as rn
from dbo.PayoutInstallment
)
select a1.AccountId,a1.SubAccountId, Sum(a1.Amount_Amount) as AmountInDay, a1.[Date]
from CTE2 a1
left join CTE2 a2
on a1.AccountId = a2.AccountId and a1.[Date] > a2.[Date]
and a2.rn = a1.rn+1
group by a1.[Date], a1.AccountId, a1.SubAccountId
order by a1.[Date] desc
EDIT
Sample Data
AccountId| SubAccountId| AmountInDay | Date
---------------------------------------------
210 | 1 | 0.00 |2017-03-15 00:00:00.000
210 | 1 | 0.00 |2017-04-20 00:00:00.000
210 | 1 | 100.00 |2017-05-17 00:00:00.000
210 | 1 | 1.00 |2017-06-05 00:00:00.000
210 | 1 | 1.00 |2017-06-05 00:00:00.000
1234 | 1 | 0.00 |2017-06-05 00:00:00.000
1234 | 1 | 0.00 |2017-06-05 00:00:00.000
1234 | 1 | 1.00 |2017-06-10 00:00:00.000
1234 | 1 | 1.00 |2017-04-10 00:00:00.000
I think you can use row_number and get 2 records as below:
Select * from (
Select AccountId, SubAccountId, [Date], sum(Amount_Amount) over (partition by accountid, SubAccountId, [Date])
,RowN = Row_number() over (partition by accountid, SubAccountId, [Date] order by [date] desc)
from dbo.PayoutInstallment
) a where a.RowN <= 2
Assume one day one transaction,
;WITH cte AS(SELECT *
, ROW_NUMBER() OVER (PARTITION BY AccountId, SubAccountId ORDER BY [Date] DESC) AS Rownum
FROM PayoutInstallment
)
SELECT *
, SUM(AmountInDay) OVER (PARTITION BY AccountId, SubAccountId) AS SumLast2days
FROM cte
WHERE Rownum<=2
If you want the SUM for the last two day you need to assign a number to each day. Then bring all the data related to those days by JOIN both dataset and then perform a GROUP BY
WITH cte as (
SELECT AccountId, SubAccountId, [Date],
ROW_NUMBER() OVER (PARTITION BY AccountId, SubAccountId
ORDER BY [Date] DESC) AS rn
FROM dbo.PayoutInstallment
)
SELECT P.AccountId,
P.SubAccountId,
P.[Date],
SUM(ammount)
FROM dbo.PayoutInstallment P
JOIN cte C
ON P.[Date] = C.[Date]
AND P.AccountId = C.AccountId
AND P.SubAccountId = C.SubAccountId
WHERE rn <= 2 -- Just the last day of each account, subacount
GROUP BY P.AccountId,
P.SubAccountId,
P.[Date]
I see you are using GROUP BY, so if you want the results to be sorted after the grouping, you should use HAVING if you want otherwise you should use WHERE. Here is an example of a WHERE clause you can use in your query to get only results between the last two days.
WHERE (a1.[Date] BETWEEN GETDATE()AND GETDATE()-2)

Rank on each group without using derived table

AccountNo Account Name Transaction time Transaction Amount
A01 Name 1 01-01-2016 04:00:00 5000
A01 Name 1 01-01-2016 07:30:00 3500
A01 Name 1 01-01-2016 09:30:00 3500
A01 Name 1 01-01-2016 12:00:00 6500
A01 Name 1 02-02-2016 06:00:00 4000
A01 Name 1 01-02-2016 08:30:00 8000
A01 Name 1 01-02-2016 09:30:00 8000
A02 Name 2 05-01-2016 04:00:00 2000
A02 Name 2 05-01-2016 07:30:00 8500
A02 Name 2 08-02-2016 06:00:00 1000
A02 Name 2 09-02-2016 08:30:00 9000
I need a query without using derived table to get the records which has latest transactions for each account. Query should support Oracle or TERADATA.
Using Derived table I am able to solve it as below:
SELECT a.accountno,
a.account_name,
a.transaction_time,
a.transaction_amount
FROM acct_details a,
(SELECT accountno,
Max(transaction_time) AS Transaction_time
FROM acct_details
GROUP BY accountno) b
WHERE a.accountno = b.accountno
AND a.transaction_time = b.transaction_time;
Thanks for Help!!
Why without Derived Table?
In Teradata there's QUALIFY, but it's no Standard SQL:
SELECT *
FROM acct_details
QUALIFY RANK() OVER (PARTITION BY accountno
ORDER BY transaction_time DESC) = 1;
In Oracle you need a Derived Table:
SELECT a.accountno,
a.account_name,
a.transaction_time,
a.transaction_amount,
FROM
(
SELECT a.accountno,
a.account_name,
a.transaction_time,
a.transaction_amount,
RANK() OVER (PARTITION BY accountno
ORDER BY transaction_time DESC) as rnk
FROM acct_details a
) a
WHERE rnk = 1
You might also try Oracle's MAX/KEEP:
SELECT a.accountno,
MAX (a.account_name) KEEP (DENSE_RANK FIRST ORDER BY a.transaction_time desc) ,
MAX(a.transaction_time),
MAX (a.transaction_amount) KEEP (DENSE_RANK FIRST ORDER BY a.transaction_time desc) FROM acct_details a
GROUP BY a.accountno
You can do it using an inline view like so:
SELECT a.accountno,
a.account_name,
a.transaction_time,
a.transaction_amount
FROM (SELECT accountno,
account_name,
transaction_time,
transaction_amount,
Max(transaction_time) OVER (PARTITION BY accountno) AS max_transaction_time
FROM acct_details) a
WHERE a.transaction_time = a.max_transaction_time;
This will work on Oracle and I think it should also work on Teradata.
I assume here that when you say you want to avoid a derived table, you mean you want to avoid joining the table to itself.
try this query:
SELECT [Transaction time],[Account Name],
lead([Transaction time ],1,1) OVER (ORDER BY [Account Name])
FROM [dbo].[acct_details]
this should help you

How to determine the maximum value for each category in SQL?

My table has records like below:
ID EmpID EffectiveDate PayElement Amount ComputeType AddDeduction
42 ISIPL001 2010-04-16 00:00:00.000 Basic 8000.00 On Attendance Addition
43 ISIPL001 2010-04-01 00:00:00.000 Con 2000.00 On Attendance Addition
44 ISIPL001 2010-04-01 00:00:00.000 HRA 2000.00 On Attendance Addition
54 ISIPL001 2011-01-01 00:00:00.000 Basic 15000.00 On Attendance Addition
55 ISIPL001 2011-01-01 00:00:00.000 Con 6000.00 On Attendance Addition
57 ISIPL001 2011-01-01 00:00:00.000 HRA 6000.00 On Attendance Addition
61 ISIPL001 2010-07-10 00:00:00.000 Basic 12000.00 On Attendance Addition
66 ISIPL001 2010-07-10 00:00:00.000 HRA 4200.00 On Attendance Addition
68 ISIPL001 2010-07-10 00:00:00.000 Con 5600.00 On Attendance Addition
I want the result display below:
i.e for each pay element available in my database, I need to record which is having maximum date for each pay element.
So my output should be like given below:
54 Basic 15000
55 Con 6000
57 HRA 6000
Try this:
SELECT ID,
PayElement,
Amount
FROM (
SELECT a.*,
RANK() OVER(PARTITION BY PayElement ORDER BY EffectiveDate DESC) AS rn
FROM <YOUR_TABLE> a
) a
WHERE rn = 1
;with cte as
(
select *,
row_number() over(partition by PayElement order by EffectiveDate desc) as rn
from YourTable
)
select
ID,
PayElement,
Amount
from cte
where rn = 1
Try this.
select
T.ID,
T.PayElement,
T.Amount
from
Test T inner join (select MAX(T_DATE.EffectiveDate) as MAX_DATE, T_DATE.PayElement from Test T_DATE group by T_DATE.PayElement) T_DATE on (T.PayElement = T_DATE.PayElement) and (T.EffectiveDate = T_DATE.MAX_DATE)
order by
T.ID
Select a.Id,
a.PayElement,
a.Amount
From dbo.YourTable a
Join
(
Select PayElement,
Max(EffectiveDate) as[MaxDate]
From dbo.YourTable
Group By PayElement
)b on a.PayElement = b.PayElement
And a.EffectiveDate = b.MaxDate
try something like
Select
a.ID, a.PayElement, a.Amount
From MyTable a
Inner Join (
Select PayElement, max(EffectiveDate) as MaxDate From MyTable Group By PayElement
) sub on a.EffectiveDate = sub.MaxDate and a.PayElement = sub.PayElement
select
Id, PayElement, Amount
from
YourTable a
inner join
(select
Id, PayElement, max(EffectiveDate) as EffectiveDate
from
YourTable
group by
PayElement, Id) b
on
a.Id = b.Id