Summing row before in a condition (SQL) - sql

I have a spreadsheet where sales data is interspersed with other data in columns. The column headings for S always end with the sum between I(row before)+P(current row) - I(Current row). I would like the data to sum for each row only. I need to do this with SQL queries.
for example :
if the week is 201520, it will return 'X',
but if it isn't week 201520, then S(Column) = I(week 201547) + P(week 201548) - I(Week 201548)
Currently my queries is like this, but I don't get the logic in query for this case, can anybody help me?
select c.[SHIP TO CODE],Area,[Dealer/Account],
c.[PRODUCT CODE],c.Model,c.Category,c.WEEK,c.I,c.P,c.S
from(select distinct b.[SHIP TO CODE],rp.Model,rp.Category,b.[PRODUCT CODE],b.WEEK,b.QTY,
case when TYPE = 'I' then 'I' end as I,
case when TYPE = 'P' then 'P' end as P,
case when WEEK = '201550' then 'X' end as S from
(
select [SHIP TO CODE],[PRODUCT CODE],WEEK,qty,TYPE from Rekap
a
union
select [Ship-to party],Material,[Week-Ok],[1st G/I Qty],category from
SOT left join
SDate on [Tgl SAP] = [1st G/I Date]
)b
left join [Ref Prod]rp
on b.[PRODUCT CODE] = rp.ProductID
where WEEK is not null
)
c
left join [Ref Dealer]rd
on c.[SHIP TO CODE] = rd.[Ship To Code]
order by [Ship To Code],WEEK ASC

select * into #a from (
select
case when abcd.WEEK = '201520' then 'X' end as S,*
from(select abc.Area,abc.Channel,abc.[Dealer/Account],abc.[PRODUCT CODE],rp.Model,rp.Category,abc.week,abc.I,abc.P
from (select ab.[SHIP TO CODE],rd.Area,rd.Channel,rd.[Dealer/Account],ab.[PRODUCT CODE],
ab.WEEK,case when TYPE = 'I' then isnull(QTY,0) end as I,
case when TYPE = 'P' then isnull(qty,0) end as P
from(
select [SHIP TO CODE],[PRODUCT CODE],WEEK,qty,TYPE from Rekap
a
union all
select [Ship-to party],Material,[Week-Ok],[1st G/I Qty],category from
SOT left join
SDate on [Tgl SAP] = [Billing Date])
ab
left join [Ref Dealer]rd
on ab.[SHIP TO CODE] = rd.[Ship To Code]
)abc
left join
[Ref Prod]rp on rp.ProductID = abc.[PRODUCT CODE]
)abcd
--order by abcd.[Dealer/Account],abcd.WEEK
) a
select Area, Channel, [Dealer/Account], [Product Code], model, category, week,
CASE WHEN I IS NULL THEN 'P' WHEN P IS NULL THEN 'I' END type,
SUM(ISNULL(I,0)+ISNULL(p,0)) amount
into #b
from #a
where week is not null
group by area, channel,[dealer/account], [product code], model, category, week,
CASE WHEN I IS NULL THEN 'P' WHEN P IS NULL THEN 'I' END
order by week
--Grouping all, put into temp table
select Area, Channel, [Dealer/Account], [Product Code], model, category, week,
SUM(ISNULL(I,0)) I, SUM(ISNULL(p,0)) p
into #c
from #a
where week is not null
group by area, channel,[dealer/account], [product code], model, category, week
order by week
select *,(select MAX(week) from #c where a.week>#c.week
--IF NOT NEEDED
--and
--a.area=#c.area and a.channel=#c.channel and a.[dealer/account]=#c.[dealer/account] and a.[product code]=#c.[product code]
--and a.model=#c.model and a.category=#c.category
-- END OF
) lastweek
into #d
from #c a
select a.*, a.P-a.I+b.I s from #d a left join #d b on
a.area=b.area and a.channel=b.channel and a.[dealer/account]=b.[dealer/account] and a.[product code]=b.[product code]
and a.model=b.model and a.category=b.category and
a.lastweek=b.week
order by area, channel,[dealer/account], [product code], model, category, week

Related

SQL Server Query: How do I get maximum counts for specific groupings?

We have a table with the following information:
Account ID, Touch Number, Type, Touch Date, and Stage (ranked 1-3, 1 if touch number < 50, 2 if 51-100, 3 if > 100).
Screenshot from table
I am looking to write a query that captures the type with the most touches at each stage for each account, looking something like this:
Output I am looking to receive
Here is the current query I wrote that is not working for me:
`SELECT distinct
a.[Account ID],
a.Stage,
bb.Stage1TopType,
bb.TypeCount_1,
c.Stage2TopType,
c.TypeCount_2,
d.Stage3TopType,
d.TypeCount_3
FROM SFAX.dbo.LinearTest as a
--STAGE 1
LEFT JOIN
(
SELECT
a.[Account ID],
a.Type as Stage1TopType,
Max(b.TouchCount) as TypeCount_1
FROM SFAX.dbo.LinearTest as a
LEFT JOIN
(
SELECT
[Account ID],
Type,
COUNT(TouchNumber) as TouchCount
FROM SFAX.dbo.LinearTest
WHERE Stage = 1
GROUP BY [Account ID], Type
) as b on a.[Account ID] = b.[Account ID]
WHERE a.Stage = 1
GROUP BY a.[Account ID], a.Type
) as bb on a.[Account ID] = bb.[Account ID]
--STAGE 2
LEFT JOIN
(
SELECT
a.[Account ID],
a.Type as Stage2TopType,
Max(b.TouchCount) as TypeCount_2
FROM SFAX.dbo.LinearTest as a
LEFT JOIN
(
SELECT
[Account ID],
Type,
COUNT(TouchNumber) as TouchCount
FROM SFAX.dbo.LinearTest
WHERE Stage = 2
GROUP BY [Account ID], Type
) as b on a.[Account ID] = b.[Account ID]
WHERE a.Stage = 2
GROUP BY a.[Account ID], a.Type
) as c on a.[Account ID] = c.[Account ID]
--STAGE 3
LEFT JOIN
(
SELECT
a.[Account ID],
a.Type as Stage3TopType,
Max(b.TouchCount) as TypeCount_3
FROM SFAX.dbo.LinearTest as a
LEFT JOIN
(
SELECT
[Account ID],
Type,
COUNT(TouchNumber) as TouchCount
FROM SFAX.dbo.LinearTest
WHERE Stage = 3
GROUP BY [Account ID], Type
) as b on a.[Account ID] = b.[Account ID]
WHERE a.Stage = 3
GROUP BY a.[Account ID], a.Type
) as d on a.[Account ID] = d.[Account ID]
`
Please let me know if you have any suggestions on how I can receive my desired output.
I believe a simple ROW NUMBER window function should be enough.
;WITH MostTouchesByAccountStage AS
(
SELECT
T.[Account ID],
T.Stage,
T.TouchNumber,
T.Type,
T.TouchDate,
Ranking = ROW_NUMBER() OVER ( -- Generate a ranking
PARTITION BY
T.[Account ID], -- That will reset with each different value of Account and Stage
T.Stage
ORDER BY
T.TouchNumber DESC) -- And is ordered by TouchNumber descendently
FROM
YourTable AS T
)
SELECT
T.*
FROM
MostTouchesByAccountStage AS T
WHERE
T.Ranking = 1
What I am looking for is the Type that appears the greatest number of
times in each stage.
You will need to perform the count first, then decide which of these has the highest value. Below you will see the count performed in a "derived table", then row_number() is used to assign a value of 1 to the highest count, and finally we only return te rows with that value of 1
SELECT
[Account ID]
, Stage
, TouchNumber
, Type
, TouchDate
, type_count
FROM (
SELECT
[Account ID]
, Stage
, TouchNumber
, Type
, TouchDate
, type_count
, ROW_NUMBER() OVER (PARTITION BY [Account ID], Stage ORDER BY type_count DESC, Type) AS rn
FROM (
SELECT
[Account ID]
, Stage
, TouchNumber
, Type
, TouchDate
, COUNT( * ) OVER (PARTITION BY [Account ID], Stage, Type) AS type_count
FROM YourTable AS T
) sq
) d
WHERE rn = 1
ORDER BY
[Account ID]
, Stage
nb. there might be more than one row with the same high value but only one row can be returned, if you want more then one row with for a tie use dense_rank() instead

SQL Access Sentence

I been trying to use this sentences that i made in SQL Server Management Studio, on access with no luck, after hours googling, i think they use different languages, can someone help me turn these in Access language?
select c.id_client 'Client ID',
c.client_name 'First Name'
c.client_lname 'Last Name'
from client c join bills b
on c.id_client = b.id_client join bill_detail d
on d.bill_num=b.bill_num
where month (b.date)=3
and year(b.date)= year(getdate())
group by c.id_client, c.client_name,c.client_lname
having d.price > (select avg(prirce) from bill_detail)
select s.id_seller 'Seller ID',
s.seller_name 'First Name',
s.seller_lname 'Last Name',
avg(quantity*d.price),
from sellers s join bills b
on v.id_seller=b.id_seller join bill_detail d
on b.bill_num = d.bill_num
group by s.id_seller, s.seller_name, s.seller_lname
having avg (quantity*d.price) < (select avg(quantity*d.price) from
bill_detail)
select date 'Date',
sum(quantity) 'Tickets Sold',
sum(quantity*d.price) 'Total Amount Sold',
avg(quantity*d.price) 'Average Amount Sold',
from bills b join bill_detail d
on b.bill_num = d.bill_num
group by date
Sry, they were in spanish, hence the awfull english. And thanks in advance.
Useful references:
Converting Access Queries to SQL Server
T-SQL Equivalents for Microsoft Access VBA Functions
I think these will work.. (it's been a while)
SELECT
client.id_client [client id]
, client.client_name [first name]
, client.client_lname [last name]
FROM (client
JOIN bills ON client.id_client = bills.id_client)
JOIN bill_detail ON bill_detail.bill_num = bills.bill_num
WHERE MONTH(bills.date) = 3
AND YEAR(bills.date) = YEAR(DATE())
GROUP BY
client.id_client
, client.client_name
, client.client_lname
HAVING d.price > (
SELECT
AVG(prirce)
FROM bill_detail
)
;
For some reason Access likes parentheses in the from clause. No idea why. There should be MONTH() & YEAR() . Don't recall if Access like table aliases, so I removed them and don't use single quotes for column labels (don't do this is SQL Server either).
SELECT
sellers.id_seller [seller id]
, sellers.seller_name [first name]
, sellers.seller_lname [last name]
, AVG(quantity * bill_detail.price)
FROM (sellers
JOIN bills ON v.id_seller = bills.id_seller)
JOIN bill_detail ON bills.bill_num = bill_detail.bill_num
GROUP BY
sellers.id_seller
, sellers.seller_name
, sellers.seller_lname
HAVING AVG(quantity * bill_detail.price) < (
SELECT
AVG(quantity * bill_detail.price)
FROM bill_detail
)
;
Aside from table & column aliases changes these 2 should be ok.
SELECT
datex [date]
, SUM(quantity) [tickets sold]
, SUM(quantity * bill_detail.price) [total amount sold]
, AVG(quantity * bill_detail.price) [average amount sold]
FROM (bills
JOIN bill_detail ON bills.bill_num = bill_detail.bill_num)
GROUP BY
datex
;
having d.price > (select avg(prirce) from bill_detail)
I think you should change it to avg(price) instead of avg(prirce).
(Must be spelling mistake only)

Adding an additional Inner join with mutiple tables SQL

I'm wondering how to inner join customer name-(CUSTNAM) from table rm001 to this query & have it added to my SSRS Report. Could use help adding this. Thanks
I've tried adding after the "from" saleslineitems as an "and" but it broke the SSRS report.
use n
select distinct a.[SOP Number]
--, [Item Number]
, a.[Customer Number], a.[Created Date from Sales Transaction], a.[Primary Shipto Address Code from Sales Line Item]
, a.[City from Sales Transaction],
,c.city
,case
when b.CITY <> c.city then 'Cities Do Not Match'
when c.city = '' then 'Cities do not Match'
when isnull(c.city,'1') = '1' then 'Cities Do Not Match'
else ''
end as [validate cities]
,b.USERDEF1 as GP_F
, c.f_number as EZ_F
,case
when b.USERDEF1 <> c.f_number then 'Fs do not Match'
when b.USERDEF1 = '' then 'No F in GP'
else ''
end as [validate Fs]
, c.f_expiration
,case
when c.f_expiration <= getdate() then ' F EXPIRED '
when c.f_expiration <= DATEADD(d,15,getDate()) then 'F expiring soon'
--when c.f_expiration >= dateAdd(d,61,getdate()) then 'valid F Expiration'
else ''
end as [valid f date]
--,( select top(1) c.f_number from NBS_BoundBook..contacts where c.f_number = b.userdef1 order by c.uid desc )
--, a.*
from SalesLineItems a
inner join rm00102 b on a.[customer number] = b.CUSTNMBR and a.[Primary Shipto Address Code from Sales Line Item] = b.ADRSCODE
left join NBS_BoundBook..contacts c on Replace(Replace(ltrim(rtrim(b.USERDEF1)),CHAR(10),''),CHAR(13),'') =
( select top(1) Replace(Replace(ltrim(rtrim(c.f_number)),CHAR(10),''),CHAR(13),'') from NBS_BoundBook..contacts
where Replace(Replace(ltrim(rtrim(c.f_number)),CHAR(10),''),CHAR(13),'') = Replace(Replace(ltrim(rtrim(b.USERDEF1)),CHAR(10),''),CHAR(13),'')
and c.city= b.CITY order by c.uid desc )
where [sop type] = 'Order'
and [Created Date from Sales Transaction] >= dateAdd(d,-3, getDate())
and [Item Tracking Option] in ( 'Serial Numbers' )
order by a.[Customer Number]
Something like this should work:
.....
FROM SalesLineItems a
INNER JOIN rm00102 b
ON a.[customer number] = b.CUSTNMBR
AND a.[Primary Shipto Address Code from Sales Line Item] = b.ADRSCODE
INNER JOIN rm001 cust
ON cust.[customer number] = a.[customer number]
LEFT JOIN NBS_BoundBook..contacts c
....

Comma-separated List of Results

I have a fairly basic query that essentially returns a SUM total for invoice line net, for each customer, where there was a certain discount given.
As part of this, I want to return the invoice numbers that each discount applied to, as a comma separated list.
This is essential as it's being fed into another piece of software that only accepts the data in this format.
I could format in Excel as this is where the data will end up, however I'd rather do it in the query directly.
I'm getting my head muddled trying to use the FOR XML PATH function to do this.
Below is the current query, which returns one row per Discount Group, Customer, Discount % given with the sum totals
Field for invoice number is invoice_header.ih_number
SELECT variant_discount_group.vdg_node_path AS 'Discount Group' ,
customer_detail.cd_statement_name AS 'Customer Name' ,
invoice_line_item.ili_discount_percent AS 'Discount' ,
SUM(( CASE WHEN invoice_header.ih_credit = 1 THEN -1
ELSE 1
END ) * invoice_line_item.ili_qty) AS 'Qty' ,
SUM(( CASE WHEN invoice_header.ih_credit = 1 THEN -1
ELSE 1
END ) * invoice_line_item.ili_net) AS 'Total Net'
FROM invoice_header
JOIN invoice_line_item ON invoice_line_item.ili_ih_id = invoice_header.ih_id
JOIN variant_detail ON variant_detail.vad_id = invoice_line_item.ili_vad_id
JOIN variant_setting ON variant_setting.vas_vad_id = variant_detail.vad_id
JOIN customer_detail ON customer_detail.cd_id = invoice_header.ih_cd_id
LEFT JOIN variant_discount_group ON variant_discount_group.vdg_id = variant_setting.vas_vdg_id
WHERE invoice_header.ih_datetime BETWEEN #DateFrom
AND #DateTo
AND ISNULL(variant_discount_group.vdg_node_path, '') LIKE #VDGroup
+ '%'
AND invoice_line_item.ili_discount_percent BETWEEN #DiscFrom
AND #DiscTo
GROUP BY variant_discount_group.vdg_node_path ,
customer_detail.cd_statement_name ,
invoice_line_item.ili_discount_percent
ORDER BY variant_discount_group.vdg_node_path ,
customer_detail.cd_statement_name ,
invoice_line_item.ili_discount_percent
try this
WITH cte
AS ( SELECT variant_discount_group.vdg_node_path AS [Discount Group] ,
customer_detail.cd_statement_name AS [Customer Name] ,
invoice_line_item.ili_discount_percent AS [Discount] ,
( CASE WHEN invoice_header.ih_credit = 1 THEN -1
ELSE 1
END ) * invoice_line_item.ili_qty AS [Qty] ,
( CASE WHEN invoice_header.ih_credit = 1 THEN -1
ELSE 1
END ) * invoice_line_item.ili_net AS [Total Net] ,
invoice_header.ih_number AS [invoice]
FROM invoice_header
JOIN invoice_line_item ON invoice_line_item.ili_ih_id = invoice_header.ih_id
JOIN variant_detail ON variant_detail.vad_id = invoice_line_item.ili_vad_id
JOIN variant_setting ON variant_setting.vas_vad_id = variant_detail.vad_id
JOIN customer_detail ON customer_detail.cd_id = invoice_header.ih_cd_id
LEFT JOIN variant_discount_group ON variant_discount_group.vdg_id = variant_setting.vas_vdg_id
WHERE invoice_header.ih_datetime BETWEEN #DateFrom
AND #DateTo
AND ISNULL(variant_discount_group.vdg_node_path, '') LIKE #VDGroup
+ '%'
AND invoice_line_item.ili_discount_percent BETWEEN #DiscFrom
AND
#DiscTo
)
SELECT a.[Discount Group] ,
a.[Customer Name] ,
a.[Discount] ,
SUM(a.[Qty]) AS Qty ,
SUM(a.[Total Net]) AS [Total Net] ,
SUBSTRING(( SELECT ', ' + CONVERT(VARCHAR, b.[invoice])
FROM (SELECT DISTINCT
[invoice],
[Discount Group],
[Customer Name],
[Discount]
FROM cte) AS b
WHERE a.[Discount Group] = b.[Discount Group]
AND a.[Customer Name] = b.[Customer Name]
AND a.[Discount] = b.[Discount]
FOR
XML PATH('')
), 2, 1000) AS [List of invoices]
FROM cte AS a
GROUP BY a.[Discount Group] ,
a.[Customer Name] ,
a.[Discount]
ORDER BY a.[Discount Group] ,
a.[Customer Name] ,
a.[Discount]
I don't know about performance issues but you could create a function returning a VARCHAR. Call that function in your select statement and as parameter give your reference for your invoicenumbers.
in the Function you would have a cursor for all rows of Invoicenumbers and iterate over it and concatenate into the return value.
This is probably quick and dirty and ressource intensive.

Calculate difference between two columns sql

in my SQL Query i am Calculating column values by using CASE WHEN THEN ELSE END Condition.
Now i want to find difference between computed column and normal column
My Query
SELECT T.Ticket [Ticket],
TT.TicketType [Ticket Type],
T.Dependency [Dependency],
CASE
WHEN (
SELECT TOP 1 f1.UpdatedOn
FROM TicketTypeFollowUp AS f1
WHERE f1.UpdatedOn < T.UpdatedOn
AND f1.Ticket = 61423
ORDER BY f1.UpdatedOn DESC
) IS NULL
THEN Ticket.TicketRaisedOn
ELSE (
SELECT TOP 1 f1.UpdatedOn
FROM TicketTypeFollowUp AS f1
WHERE f1.UpdatedOn < T.UpdatedOn
AND f1.Ticket = 61423
ORDER BY f1.UpdatedOn DESC
)
END [Start Date],
T.UpdatedOn [End Date],
L.EmpName [Updated By]
FROM dbo.TicketTypeFollowUp T
LEFT JOIN dbo.Ticket
ON T.Ticket = Ticket.Code
LEFT JOIN dbo.TicketType TT
ON T.TicketType = TT.Code
LEFT JOIN LoginUser L
ON T.UpdatedBy = L.Code
WHERE Ticket = 61423
Query Result
Ticket Type Dependency Start Date End Date Updated By
61423 FLM AGS 2013-01-22 15:50:08.757 2013-01-22 18:35:50.893 Kedar S
I want one more column which displays End Time - Start Time I have used CASE hence i am unable to compute difference.
Database is SQL SERVER 2008
with lastUpdate(ticket, lastUpdate) as (
select ticket,
max(updateOn)
from TicketTypeFollowUp
group by ticket)
SELECT T.Ticket [Ticket],
TT.TicketType [Ticket Type],
T.Dependency [Dependency],
coalesce(lastUpdate, ticketRaisedOn) [Start Date],
T.UpdatedOn [End Date],
datediff(mi, coalesce(lastUpdate, ticketRaisedOn), T.UpdatedOn) durationMins,
L.EmpName [Updated By]
FROM dbo.TicketTypeFollowUp T
LEFT JOIN dbo.Ticket
ON T.Ticket = Ticket.Code
LEFT JOIN dbo.TicketType TT
ON T.TicketType = TT.Code
LEFT JOIN LoginUser L
ON T.UpdatedBy = L.Code
left join lastUpdate lu on t.ticket = lu.ticket
WHERE Ticket = 61423
You can use your current query as a CTE or a derived table. Here is an example using a CTE:
;WITH CTE AS
(
-- your current query here
)
SELECT *, DATEDIFF(MINUTE,[Start Date],[End Date]) [End Time - Start Time]
FROM CTE