sql partiton by suppress repeating values - sql

Using SQL Server (2005/2008)
Is there an easy way to suppress the repeating sub & grand totals?
select h.salesmanno
,c.custname
,h.amt
,sum(h.amt) over (partition by salesmanno) as subtotal
,sum(h.amt) over (partition by null) as grandtotal
from hdr h, cust c WHERE h.custno = c.custno
and h.hdate = '6/8/2009'
basically suppress (or null) except the last position, before the group change
Thanks!!

What database is this? On SQL Server, something like this would do:
select
salesmanno, custname, amt
, case when subtotal_no = subtotal_count then subtotal end as subtotal
, case when total_no = total_count then subtotal end as total
from (
select
h.salesmanno
, c.custname
, h.amt
, sum(h.amt) over (partition by salesmanno) as subtotal
, sum(h.amt) over (partition by null) as grandtotal
, row_number() over (partition by salesmanno order by custname) as subtotal_no
, row_number() over (partition by null order by salesmanno, custname) as as total_no
, count(*) over (parition by salesmanno) as subtotal_count
, count(*) over (parition by null) as total_count
from hdr h, cust c
WHERE h.custno = c.custno
and h.hdate = '6/8/2009'
) a
order by total_no
Shorter version, more sorting for the database, maybe less obvious what's going on:
select
salesmanno, custname, amt
, case when subtotal_no = 1 then subtotal end as subtotal
, case when total_no = 1 then subtotal end as total
from (
select
h.salesmanno
, c.custname
, h.amt
, sum(h.amt) over (partition by salesmanno) as subtotal
, sum(h.amt) over (partition by null) as grandtotal
, row_number() over (partition by salesmanno order by custname desc) as subtotal_no
, row_number() over (partition by null order by salesmanno desc, custname desc) as as total_no
from hdr h, cust c
WHERE h.custno = c.custno
and h.hdate = '6/8/2009'
) a
order by total_no desc
Alternatively, using ROLLUP to generate subtotal and total rows:
select
h.salesmanno
, c.custname
, sum(h.amt) as amt
from hdr h, cust c
WHERE h.custno = c.custno
and h.hdate = '6/8/2009'
group by
h.salesmanno
, c.custname
with rollup
order by
h.salesmanno
, c.custname
To get the results in the proper order, change the order by to something like this:
order by
grouping(h.salesmanno)
, h.salesmanno
, grouping(c.custname)
, c.custname

Nest this in a subquery and add your filter in a WHERE:
SELECT *
FROM (
select h.salesmanno ,c.custname ,h.amt ,sum(h.amt) over (partition by salesmanno) as subtotal
,sum(h.amt) over (partition by null) as grandtotal
from hdr h, cust c WHERE h.custno = c.custno and h.hdate = '6/8/2009'
) AS X
WHERE whatever

Related

Bring next value after condition

I am trying to fetch the next value after the condition is found. In this case, it is a row from 13/05/2021 the result I want to see is the row from 19/05/2021 Cte and CTE1 bring correct results.
I can't figure out what is wrong with my query.
<with cte as
(
select
customerid
,max(timestamp) as [Case Submitted]
,row_number() over (partition by [CustomerId] order by [CustomerId] ,max([timestamp]) desc) as rownum
from Table1
where substatus = 'Case Submitted'
and timestamp > '2021-01-01'
Group by
customerid
,timestamp
)
,CTE2 as
(
Select *
from cte
Where rownum = 1
),
CTE3 as
(
select
PS.customerid
,(PS.timestamp) as [Customer Support]
,row_number() over (partition by PS.customerid order by PS.customerid ) as rownum
from Table1 PS
left join CTE2 C2 on C2.customerid = PS.customerid and C2.[Case Submitted] > PS.timestamp and C2.rownum =1
where status = 'Customer Support'
and timestamp > '2021-01-01'
Group by
PS.customerid
,ps.timestamp
)
Select*
from CTE3>
untested notepad scribble
with CTE1 as
(
select
customerid
, [timestamp] as [Case Submitted]
, rownum = row_number() over (partition by CustomerId order by [timestamp] desc)
from Table1
where substatus = 'Case Submitted'
and [timestamp] > cast('2021-01-01' as date)
),
CTE2 AS
(
select
PS.customerid
, PS.timestamp as [Customer Support]
, rownum = row_number() over (partition by PS.customerid order by PS.timestamp)
from Table1 as PS
join CTE1 as C1
on C1.customerid = PS.customerid
and C1.[Case Submitted] > PS.[timestamp]
and C1.rownum = 1
where PS.status = 'Customer Support'
and [timestamp] > cast('2021-01-01' as date)
)
select *
from CTE2
where rownum = 1

WITH Clause Syntax error - While using Outer select

I have created a sql which is below, when i am trying to put this under outer select which will l just display the results that are rendered from below WITH clause query it is giving me error in sql server, where as working fine with Oracle.
I don't want to create a view i want to put this below ouptut in merge statement...
select custno, slipno, category, donation, unique_nm from
(
-- Here it is throwing error
with got_debit_custno (custno, slipno, category, donation, debit_custno) as
(
select custno, slipno, category, donation
, case
when category = 'CREDIT'
then 'N/A'
else custno
end
from a
)
, prep (custno, slipno, category, donation, debit_custno, rn, rdt) as
(
select dc.*
, row_number () over (partition by debit_custno, category order by donation, slipno)
, sum (donation) over (partition by debit_custno, category order by donation, slipno)
from got_debit_custno dc
)
, r (custno, slipno, category, donation, debit_custno, rn, rdt, mn) as
(
select custno, slipno, category, donation, debit_custno
, case
when rn = max(rn) over (partition by debit_custno, category)
then rn
end
, rdt, 1
from prep
where rdt <= 27000 or rn = 1
union all
select p.custno, p.slipno, p.category, p.donation, p.debit_custno
, case
when p.rn = max(p.rn) over (partition by p.debit_custno, p.category)
then p.rn
end
, p.rdt, r.mn + 1
from prep p
join r on p.debit_custno = r.debit_custno
and p.category = r.categoRy
and p.rn > r.rn
and (p.rdt <= r.rdt + 27000 or p.rn = r.rn + 1)
)
select custno, slipno, category, donation
, dense_rank () over (order by debit_custno, category, mn) as unique_nm
from r)
order by custno, unique_nm, donation
WITH must be the first keyword of the query. The previous statement must be be terminated by ; as:
;WITH got_debit_custno (custno, slipno, category, donation, debit_custno) as
(
select custno, slipno, category, donation
, case
when category = 'CREDIT'
then 'N/A'
else custno
end
from a
)
, prep (custno, slipno, category, donation, debit_custno, rn, rdt) as
(
select dc.*
, row_number () over (partition by debit_custno, category order by donation, slipno)
, sum (donation) over (partition by debit_custno, category order by donation, slipno)
from got_debit_custno dc
)
, r (custno, slipno, category, donation, debit_custno, rn, rdt, mn) as
(
select custno, slipno, category, donation, debit_custno
, case
when rn = max(rn) over (partition by debit_custno, category)
then rn
end
, rdt, 1
from prep
where rdt <= 27000 or rn = 1
union all
select p.custno, p.slipno, p.category, p.donation, p.debit_custno
, case
when p.rn = max(p.rn) over (partition by p.debit_custno, p.category)
then p.rn
end
, p.rdt, r.mn + 1
from prep p
join r on p.debit_custno = r.debit_custno
and p.category = r.categoRy
and p.rn > r.rn
and (p.rdt <= r.rdt + 27000 or p.rn = r.rn + 1)
)
select custno, slipno, category, donation
, dense_rank () over (order by debit_custno, category, mn) as unique_nm
from r
order by custno, unique_nm, donation

Find median between 2 dates

Anyone know how I can change the Total Median near bottom to show an average of the median instead? For some reason, the Total Median is always 100. Not sure what I should do.
Thanks in advance for any ideas! Current results also below.
WITH CTE AS (
SELECT DISTINCT c.CaseID AS CaseID,
DATEDIFF(d, c.CaseAddDt, coip.DispoDt) AS DaysApart
, DATEPART(month,c.CaseAddDt) AS [Month]
, DATEPART(year,c.CaseAddDt) AS [Year]
, CAST(DATEPART(year,c.CaseAddDt) AS varchar) + '|' + CASE WHEN DATEPART(month,c.CaseAddDt) IN (10,11,12) THEN CAST(DATEPART(month,c.CaseAddDt) AS varchar) ELSE '0' + CAST(DATEPART(month,c.CaseAddDt) AS varchar) END AS Srt
FROM jw50_Case c
JOIN jw50_CaseInvPers def ON def.CaseID = c.CaseID
AND def.InvolveTypeMasterCode = 1
JOIN
jw50_CountInvPers coip ON coip.CaseID = c.CaseID
AND coip.CaseInvPersID = def.CaseInvPersID
AND coip.DispoCode IN ('CODE','CODE')
AND coip.CountNum > 0
OUTER APPLY (
SELECT TOP 1 caz.CaseAgencyID
FROM jw50_CaseAgency caz
WHERE caz.CaseID = c.CaseID
AND caz.AgencyCode = 'ABC'
AND caz.NumberTypeCode IN ('i#','in#')) caz
WHERE
EXISTS (SELECT 1 FROM jw50_CaseAttributes ca WHERE ca.CaseID = c.CaseID AND ca.CaseAttributeCode = 'oa7')
AND caz.CaseAgencyID IS NOT NULL
AND c.CaseStatusCode <> 'AAA'
AND c.CaseAddDt BETWEEN '01/01/2017' AND '08/01/2017'
AND c.CaseAddDt <= coip.DispoDt)
SELECT a.CaseID,
a.Month
, a.Year
, a.DaysApart
, a.Srt
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY a.DaysApart) OVER (PARTITION BY a.Month, a.Year) AS MonMedian
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY a.DaysApart) OVER (PARTITION BY 1) AS TotalMedian
FROM CTE a
Results:

How can I change these into columns?

I've tried using CTE, but haven't been able to figure it out. I want to change the multiple rows into one row with multiple columns going accross. Any way to go about this...
Current Result
ern CostPool
111 NULL
111 5
Desired Result
ern CostPool1 CostPool2
111 NULL 5
SELECT first_name, last_name, ern, pc, title, TitleDesc, OfficeTitle, SUM(earned) earned, fypaydate, q
, [RMTS, Support, or Partial Quarter], SUM(CAST([Staff Employment Status] AS INT)) sumEmpStatus, SUM(CAST(countisMHy AS INT)) sumcountisMHy, SUM(CAST(sumisMHy AS INT)) sumisMHy1
, SUM(CAST(sumEligible AS INT)) sumEligible1
, CostPool
FROM (
SELECT
e.first_name, e.last_name
, fss.ern
, fss.pc
, fss4.title
, u.OfficeTitle
, t.TitleDesc
, SUM(fss.gross*fss.[percent]) earned
, fss.fypaydate, fss.q
, cpayfss3, cpaypdq
, CASE WHEN cpayfss3 = cpaypdq THEN '1' --full q
WHEN cpayfss3 < cpaypdq THEN '2' --part q
ELSE 'Check'
END [RMTS, Support, or Partial Quarter]
, CASE WHEN COUNT(DISTINCT rc.isMHy) = 2 THEN '9' --split
WHEN fss.pc = 'A' AND COUNT(DISTINCT rc.isMHy) = 1 AND SUM(CAST(rc.isMHy AS INT)) > 0 THEN '1' --full
WHEN fss.pc IN ('X', 'O', 'W', 'L', 'K') AND SUM(CAST(rc.isMHy AS INT)) > 0 THEN '2' --part
ELSE '0'
END [Staff Employment Status]
, COUNT(DISTINCT rc.isMHy) countisMHy
, SUM(CAST(rc.isMHy AS INT)) sumisMHy
, SUM(CAST(rc.Eligible AS INT)) sumEligible --count distinct too?
, rc.CostPool
FROM [FIN_DataMart].[dbo].[FSSpaydetl_NEW] fss
LEFT JOIN FIN_DataMart.[dbo].[FSSRC_NEW] rc
ON fss.newrc = rc.RC
AND fss.fypaydate = rc.FY
INNER JOIN
(
SELECT ern, fypaydate, q, COUNT(DISTINCT paydate) cpayfss3
FROM [FIN_DataMart].[dbo].[FSSpaydetl_NEW]
GROUP BY fypaydate, q, ern
) fss3
ON fss.ern = fss3.ern
AND fss.fypaydate = fss3.fypaydate
AND fss.q = fss3.q
LEFT JOIN
(
SELECT COUNT(DISTINCT paydate) cpaypdq, fy, q
FROM [FIN_DataMart].[dbo].[FSSPayDateQ]
GROUP BY fy, q
) pdq
ON fss.fypaydate = pdq.fy
AND fss.q = pdq.q
LEFT JOIN
[FIN_DataMart].[dbo].FSSEmployeeInfo e
ON fss.ern = e.ern
INNER JOIN
(
SELECT DISTINCT ern, title, tlvl, fy, q, ROW_NUMBER() OVER (PARTITION BY ern, fy, q ORDER BY title DESC) rn
FROM [FIN_DataMart].[dbo].[FSSpaydetl_NEW]
) fss4
ON fss.ern = fss4.ern
AND fss.fypaydate = fss4.fy
AND fss.q = fss4.q
AND fss4.rn = '1'
LEFT JOIN
(
SELECT TCode, TLevel, GenericTDesc as TitleDesc, EED,
ROW_NUMBER() OVER (PARTITION BY TCode, TLevel ORDER BY EED DESC) rn
FROM [FIN_DataMart].[dbo].FSATitle
) t
ON fss4.title = t.TCode
AND case when fss4.tlvl = '' THEN '01' WHEN fss4.tlvl IS NULL THEN '01' ELSE fss4.tlvl END = t.TLevel
AND t.rn = 1
LEFT JOIN FIN_DataMart.[dbo].[FSSUserERN] u
ON fss.ern = u.ern
WHERE fss.fypaydate = 2015
AND fss.q = 1
AND fss.obj <> '049' AND fss.obj NOT LIKE 'x%'
AND fss.title NOT IN ('10209', '1020B', '10234', '10232', '20202', '21205', '30086', '34201')
GROUP BY
fss.ern
, fss.pc
, fss4.title
, fss.fypaydate, fss.q
, cpayfss3, cpaypdq
, rc.CostPool
, t.TitleDesc
, e.first_name
, e.last_name
, u.OfficeTitle
HAVING SUM(CAST(rc.Eligible AS INT)) >=1
) A
GROUP BY
first_name, last_name, ern, pc, title, fypaydate, q
, [RMTS, Support, or Partial Quarter]
, OfficeTitle
, TitleDesc
, CostPool
ORDER BY first_name, last_name, fypaydate, q
You can look into using the Pivot operator to convert your rows into columns.
https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
That method would work, although your sample data and expected result do not quite match the massive query you have posted so I cannot provide a more specific example until you provide more test data/expected outputs (and table schema).

SQL query for Pricing analysis

Facing issue to find the Min and Max pricing status on the column YearMonth,
Below is my table data
YearMonth STATE ProductGroup LocaProdname Price
201407 MH AIRTEL AIRTEL-3G 10,000
201208 GJ IDEA IDEA-3G 1,200
201406 WB AIRCEL AIRCEL PERPAID 5,866
201407 DL TATA DOCOMA TATA LANDLINE 8,955
201207 KAR VODAFONE VODAFONE-3G 7,899
201312 MH AIRTEL AIRTEL-3G 15,000
201408 GJ IDEA IDEA-3G 25,000
I require below output:
YearMonth STATE ProductGroup LocaProdname Price Indictor-YEAR
201407 MH AIRTEL AIRTEL-3G 10,000 MAX
201312 MH AIRTEL AIRTEL-3G 15,000 MIN
201408 GJ IDEA IDEA-3G 25,000 MAX
201208 GJ IDEA IDEA-3G 1,200 MIN
I need the Max yearmonth and min Year values values.
If I understand correctly, you can do this with row_number():
select YearMonth, STATE, ProductGroup, LocaProdname, Price,
(case when seqnum_asc = 1 then 'MIN' else 'MAX' end) as Indicator
from (select d.*,
row_number() over (partition by state, productgroup, localprodname
order by price asc) as seqnum_asc,
row_number() over (partition by state, productgroup, localprodname
order by pricedesc) as seqnum_desc
from data
) d
where seqnum_asc = 1 or seqnum_desc = 1;
EDIT:
Does this do what you want?
select YearMonth, STATE, ProductGroup, LocaProdname, Price,
(case when seqnum_asc = 1 then 'MIN' else 'MAX' end) as Indicator
from (select d.*,
row_number() over (partition by YearMonth
order by price asc) as seqnum_asc,
row_number() over (partition by YearMOnth
order by pricedesc) as seqnum_desc
from data
) d
where seqnum_asc = 1 or seqnum_desc = 1;
Please use Row_number with partition BY and remove unwanted code as per your need,
SELECT yearmonth,state,productgroup,locaprodname,price,operation
FROM (
SELECT * FROM (SELECT p.yearmonth,p.state,p.productgroup,p.locaprodname,p.price,'MAX' AS Operation,
Row_number() OVER( partition BY p.productgroup, p.locaprodname
ORDER BY p.price DESC) AS Row
FROM pricingtest p) AS Maxx
WHERE Maxx.row = 1
UNION ALL
SELECT * FROM (SELECT p.yearmonth,p.state,p.productgroup,p.locaprodname,p.price,'MIN' AS Operation,
Row_number() OVER( partition BY p.productgroup, p.locaprodname
ORDER BY p.price ASC) AS Row
FROM pricingtest p) AS Minn
WHERE Minn.row = 1
) AS whole
ORDER BY yearmonth,productgroup
This can be done by finding the MAX/MIN values associated with the LocaProdname,ProductGroup and State then joining in on the table where everything matches. See below, or view the fiddle at http://sqlfiddle.com/#!3/4d6bd/2
NOTE: I've added in HAVING COUNT(*) > 1 as you seem to only want ones which have changed price. (Ie. Have more than 1 entry)
SELECT p.YearMonth
,p.State
,p.ProductGroup
,p.LocaProdname
,p.Price
,CASE
WHEN p.Price = a.MaxPrice
THEN 'MAX'
WHEN p.Price = a.MinPrice
THEN 'MIN'
END AS [Indicator-YEAR]
FROM PricingTest p
INNER JOIN (
SELECT LocaProdname
,ProductGroup
,State
,MAX(Price) AS MaxPrice
,MIN(Price) AS MinPrice
FROM pricingTest
GROUP BY LocaProdname
,ProductGroup
,State
HAVING COUNT(*) > 1
) a ON a.LocaProdname = p.LocaProdname
AND a.ProductGroup = p.ProductGroup
AND a.State= p.State
AND (
a.MaxPrice = p.Price
OR a.MinPrice = p.Price
)
ORDER BY LocaProdname
EDIT: Or I just noticed it's the max/min YearMonth the user might be looking, if this is the case check out http://sqlfiddle.com/#!3/4d6bd/4 It is basically just replacing all references to Price to YearMonth.
Once you get the last and first record you can UNION results:
SELECT t.*, 'MIN' AS Indicator
FROM
myTable t LEFT JOIN
myTable t2 ON t.YearMonth = t2.YearMonth AND t2.price < t.price
WHERE t2.YearMonth IS NULL
UNION
SELECT t.*, 'MAX' AS Indicator
FROM
myTable t LEFT JOIN
myTable t2 ON t.YearMonth = t2.YearMonth AND t2.price > t.price
WHERE t2.YearMonth IS NULL
If you have several records with same highest price, above query will return all of them. Also if you only have one record in a month, it will be returned twice as both MIN and MAX.