how to use sum and max in one query - sql-server

I have a table
tblPay
(
CID bigint,
PartyIdID bigint,
PartyName varchar(50),
AgentName varchar(50),
Agent bigint,
Amount decimal(18,2),
RecAmount decimal(18,2),
OutStanding decimal(18,2)
)
I want to select sum of Amount,RecAmount group by PartyId and I also want to select Last Outstanding entry of each PartyID. For this i use following query.
SELECT DISTINCT CID,
Party.AccLedger_ID PartyID,
Party.AccLedger_Name PartyName,
Agent.AccLedger_Name AgentName,
Agent.AccLedger_ID AgentID,
sum(S.Amount) Amount,
Sum(S.RecAmount) RecAmount,
S.OutStanding
Group by PartyID,
Cid,
Party.AccLedger_ID,
Party.AccLedger_Name,
Agent.AccLedger_Name,
Agent.AccLedger_ID,
S.OutStanding
But i am unable to achieve the sum of Amount,RecAmount and Last Outstanding Record of each Party. Can someone help me here.
This is the Answer i got.

Assuming your records are inserted in tblPay.CID order, use a subquery
SELECT p.PartyID,
p.PartyName,
SUM(p.Amount) AS PartyAmount,
SUM(p.RecAmount) AS PartyRecAmount,
(SELECT TOP 1 OutStanding FROM tblPay p2 WHERE p.PartyID = p2.PartyId ORDER BY CID DESC) AS LastOutStanding
FROM tblPay p
GROUP BY p.PartyID, p.PartyName
or an OUTER APPLY:
SELECT p.PartyID,
p.PartyName,
SUM(p.Amount) AS PartyAmount,
SUM(p.RecAmount) AS PartyRecAmount,
lastRecord.OutStanding AS LastOutStanding
FROM tblPay p
OUTER APPLY
(
SELECT TOP 1 OutStanding
FROM tblPay p2
WHERE p.PartyID = p2.PartyId
ORDER BY CID DESC
) lastRecord
GROUP BY p.PartyID, p.PartyName
or, as JamieD77 suggests in his answer, use a CTE.

use a cte to get your tblPay information and join that to your other tables on the last record
WITH cte AS (
SELECT
CID,
PartyName,
SUM(Amount) OVER (PARTION BY PartyIdID) Amount,
SUM(RecAmount) OVER (PARTITION BY PartyIdID) RecAmount,
OutStanding,
-- only assuming your CID determines order since you have no date?
ROW_NUMBER() OVER (PARTITION BY PartyIdID ORDER BY CID DESC) Rn
FROM tblPay
)
SELECT Party.*,
Agent.*,
p.CID,
p.PartyName,
p.Amount,
p.RecAmount,
p.Oustanding
FROM Party JOIN Agent
JOIN cte p ON p.PartyIdID = Party.AccLedger_ID AND p.Rn = 1

Related

Query table and Select latest 2 rows (in SQL Server)

I have a table that logs all updates made to an application. I want to query the table and return the last update by [Timestamp] and the update before that for a different value [ITEM]. I'm struggling to figure out how to get what i need. I'm returning more than one record for each ID and don't want that.
;WITH cte AS
(
SELECT
ID,
LAG(ITEM) OVER (PARTITION BY ID ORDER BY timestamp DESC) AS ITEM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY timestamp DESC) RN
FROM
MyLoggingTable
WHERE
accountid = 1234
)
SELECT
cte.ID,
dl.ITEM,
DL.timestamp
FROM
cte
JOIN
MyLoggingTable DL ON cte.ID = DL.ID
WHERE
rn = 1
AND cte.ID IN ('id here | Sub select :( ..')
Is ID unique? Because if it is, your code shouldn't return duplicates. If it isn't, you will get duplicates because you are joining back to the MyLoggingTable which isn't needed. You should just move those columns (dl.Item & dl.timestamp) into the cte and return them from the cte like you did cte.ID.
I removed the LAG since you didn't return that column in your final query.
;WITH cte AS
(
SELECT
ID,
ITEM,
[timestamp],
--LAG(ITEM) OVER (PARTITION BY ID ORDER BY timestamp DESC) AS ITEM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY timestamp DESC) RN
FROM
MyLoggingTable
WHERE
accountid = 1234
)
SELECT
cte.ID,
cte.ITEM,
cte.timestamp
FROM
cte
WHERE
rn = 1
AND cte.ID IN ('id here | Sub select :( ..')
Note, if you wanted the second to the last item, as you stated in your comments, make rn=2

SQL Simple Join with two tables, but one is random

I am stuck with this. I have a simple set-up with two tables. One table is holding emailaddresses one table is holding vouchercodes. I want to join them in a third table, so that each emailaddress has one random vouchercode.
Unfortunatly I am stuck with this as there are no identic Ids to match both values. What I have so far brings no result:
Select
A.Email
B.CouponCode
FROM Emailaddresses as A
JOIN CouponCodes as B
on A.Email = B.CouponCode
A hint would be great as search did not bring me any further yet.
Edit -
Table A (Addresses)
-------------------
Column A | Column B
-------------------------
email1#gmail.com True
email2#gmail.com
email3#gmail.com True
email4#gmail.com
Table B (Voucher)
-------------------
ABCD1234
ABCD5678
ABCD9876
ABCD5432
Table C
-------------------------
column A | column B
-------------------------
email1#gmail.com ABCD1234
email2#gmail.com ABCD5678
email3#gmail.com ABCD9876
email4#gmail.com ABCD5432
Sample Data:
While joining without proper keys is not a good solution, for your case you can try this. (note: not tested, just a quick suggestion)
;with cte_email as (
select row_number() over (order by Email) as rownum, Email
from Emailaddresses
)
;with cte_coupon as (
select row_number() over (order by CouponCode) as rownum, CouponCode
from CouponCodes
)
select a.Email,b.CouponCode
from cte_email a
join cte_coupon b
on a.rownum = b.rownum
You want to randomly join records, one email with one coupon each. So create random row numbers and join on these:
select
e.email,
c.couponcode
from (select t.*, row_number() over (order by newid()) as rn from emailaddresses t) e
join (select t.*, row_number() over (order by newid()) as rn from CouponCodes t) c
on c.rn = e.rn;
Give a row number for both the tables and join it with row number.
Query
;with cte as(
select [rn] = row_number() over(
order by [Column_A]
), *
from [Table_A]
),
cte2 as(
select [rn] = row_number() over(
order by [Column_A]
), *
from [Table_B]
)
select t1.[Column_A] as [Email_Id], t2.[Column_A] as [Coupon]
from cte t1
join cte2 t2
on t1.rn = t2.rn;
Find a demo here

Latest Customer Donation And Amount

I have two tables:
Customer which has an Id column representing the customer Id.
CustomerDonation that contains CustomerId (FK), Amount and DatePayed
I'd like have all the customers together with their latest donation and the amount of that donation.
I am receiving duplicate values on my query so I will not paste it here.
You could also use the WITH TIES option
Select Top 1 With Ties *
From YourTable
Order By Row_Number() over (Partition By CustomerId Order By DatePayed Desc)
WITH
SortedDonation AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY DatePayed DESC) AS SeqID,
*
FROM
CustomerDonation
)
SELECT
*
FROM
Customer
LEFT JOIN
SortedDonation
ON SortedDonation.CustomerId = Customer.Id
AND SortedDonation.SeqId = 1
If the same customer can make multiple donations with the same DatePayed, then this will arbitrarily pick just one of them.
If you add additional fields to the ORDER BY you can deterministically pick which one you want.
Or, if you want all of them use DENSE_RANK() instead of ROW_NUMBER()
Use Row_Number() Analytic function .
Select * from (
Select customerId,Amount,DatePayed, row_number() over (partition by CustomerId order by DatePayed desc) as rowN)
as tab where rowN = 1
You only need the CustomerDonation table for this. You can join with the Customer table if you want other information of the customer.
WITH cte AS (
SELECT
CustomerId
, MAX(DatePayed) AS LastDate
FROM
CustomerDonation
)
SELECT
cd.CustomerId
, cd.Amount
, cd.DatePayed
FROM
CustomerDonation cd
JOIN cte ON cd.CustomerId = cte.CustomerId
AND cd.DatePayed = cte.LastDate

Subtract top two rows from one column using one id

does anyone know how can I subtract top two rows from one column only using one id? Here's my sample query:
SELECT top 2 a.consumption,
coalesce(a.consumption -
(SELECT b.consumption
FROM tbl_t_billing b
WHERE b.id = a.id + 1), a.consumption) AS diff
FROM tbl_t_billing a
WHERE a.customerId = '5'
ORDER BY a.dateCreated DESC
I want to know how to get the difference between the top 2 rows using one id from the consumption column using the customerId #5. I've tried but I can't get the right query for that. Can somebody help me please? Thanks!
try this:
;with cte as
(
select consumption, customerId,
row_number() over (partiton by customerid order by datecreated desc) rn
from tbl_t_billing where customerId = '5'
)
select a.customerId, a.consumption,
coalesce((a.consumption - b.consumption), a.consumption) consumption_diff
from cte a left outer join cte b on a.rn + 1 = b.rn
where a.rn = 1
declare #tbl_t_billing table(consumption int, customerId int, datecreated datetime)
insert into #tbl_t_billing
values
(10,5,'20100101'),
(7,5,'20000101'),
(9,4,'20100101'),
(5,4,'20000101'),
(8,3,'20100101'),
(3,3,'20000101'),
(7,2,'20100101'),
(3,2,'20000101'),
(4,1,'20100101'),
(2,1,'20000101')
-- get the difference between the last two consumption values for each customerId
select
customerId,
sum(consumption) diff
from(
select
customerId,
consumption *
case row_number() over(partition by customerId order by datecreated desc)
when 1 then 1 when 2 then -1
end consumption
from #tbl_t_billing
) t
group by customerId

select top 1 with a group by

I have two columns:
namecode name
050125 chris
050125 tof
050125 tof
050130 chris
050131 tof
I want to group by namecode, and return only the name with the most number of occurrences. In this instance, the result would be
050125 tof
050130 chris
050131 tof
This is with SQL Server 2000
I usually use ROW_NUMBER() to achieve this. Not sure how it performs against various data sets, but we haven't had any performance issues as a result of using ROW_NUMBER.
The PARTITION BY clause specifies which value to "group" the row numbers by, and the ORDER BY clause specifies how the records within each "group" should be sorted. So partition the data set by NameCode, and get all records with a Row Number of 1 (that is, the first record in each partition, ordered by the ORDER BY clause).
SELECT
i.NameCode,
i.Name
FROM
(
SELECT
RowNumber = ROW_NUMBER() OVER (PARTITION BY t.NameCode ORDER BY t.Name),
t.NameCode,
t.Name
FROM
MyTable t
) i
WHERE
i.RowNumber = 1;
select distinct namecode
, (
select top 1 name from
(
select namecode, name, count(*)
from myTable i
where i.namecode = o.namecode
group by namecode, name
order by count(*) desc
) x
) as name
from myTable o
SELECT max_table.namecode, count_table2.name
FROM
(SELECT namecode, MAX(count_name) AS max_count
FROM
(SELECT namecode, name, COUNT(name) AS count_name
FROM mytable
GROUP BY namecode, name) AS count_table1
GROUP BY namecode) AS max_table
INNER JOIN
(SELECT namecode, COUNT(name) AS count_name, name
FROM mytable
GROUP BY namecode, name) count_table2
ON max_table.namecode = count_table2.namecode AND
count_table2.count_name = max_table.max_count
I did not try but this should work,
select top 1 t2.* from (
select namecode, count(*) count from temp
group by namecode) t1 join temp t2 on t1.namecode = t2.namecode
order by t1.count desc
Here are to examples that you could use but the temp table use is more efficient than the view, but was done on a small data sample. You would want to check your own statistics.
--Creating A View
GO
CREATE VIEW StateStoreSales AS
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank'
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
GO
SELECT * FROM StateStoreSales
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP VIEW StateStoreSales
---Using a Temp Table
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank' INTO #TEMP
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
SELECT * FROM #TEMP
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP TABLE #TEMP

Resources