SQL Pivot swapping values in SQL Server Query - sql-server

I have two queries Sales & Forecast which I am bringing together in a UNION
These two queries at this point show correctly.
I then pivot the query to show each SKU and then a Column of Sales and then a column of Forecast but it appears that the values appear under the wrong column.
Below is my code - is there a obvious reason why it doesn't output as expected?
SELECT q.FY#, q.[Country Code], q.Family, q.Colour, q.Pack_Size, Forecast, Actuals, Forecast/nullif(Actuals,0) as Change
FROM (
SELECT FY#, [Country Code], Family, Colour, Pack_Size, Forecast, Actuals
FROM (
SELECT f.FY#, f.Attribute, f.[Country Code], f.Family, f.Colour, f.Pack_Size, sum(f.Packs) as Packs
FROM [V3.1_JDAForecast](#Country, #FY) f
group by f.FY#, f.Attribute, f.[Country Code], f.Family, f.Colour, f.Pack_Size
UNION
SELECT a.FY#, a.Attribute, a.[Country Code], a.Family, a.Colour, a.Pack_Size, sum(a.Packs) as Packs
FROM [V3.1_JDAActuals](#Country, #FY) as a
group by a.FY#, a.Attribute, a.[Country Code], a.Family, a.Colour, a.Pack_Size
) src
PIVOT
(
SUM(Packs)
for Attribute in ([Actuals], [Forecast])
) piv
) q

Related

Select n random rows from table per group of codes

I have a table full of customer details from insurance policies or quotes. Each one is assigned an output code that relates to a marketing campaign and each occurs 4 times, one per "batch" which just represents a week in the month. I need to select a random 25 percent of the rows per code, per batch number (1-4) to put into another table so I can then hold those rows back and prevent the customer being marketed to.
All the solutions I've seen on stack so far instruct how to do this for a specific number of rows per group using a ROW_NUMBER in an initial CTE query then selecting from that where rn <= a given number. I need to do this but select 25 percent of each group instead.
I've tried this solution but the specific row number doesn't move me any further forward;
Select N random rows in group
Using the linked solution, this is how my code currently is without a complete where clause because I know this isn't quite what I need.
;WITH AttributionOutput AS (
SELECT [Output Code], BatchNo, MonthandYear
FROM [dbo].[Direct_Marketing_UK]
WHERE MonthandYear = 'Sep2019'
And [Output Code] NOT IN ('HOMELIVE','HOMELIVENB','HOMENBLE')
GROUP BY [Output Code], BatchNo, MonthandYear
HAVING COUNT(*) >= 60
)
, CodeandBatch AS (
SELECT dmuk.PK_ID,
dmuk.MonthandYear,
dmuk.PackNo,
dmuk.BatchNo,
dmuk.CustomerKey,
dmuk.URN,
dmuk.[Output Code],
dmuk.[Quote/Renewal Date],
dmuk.[Name],
dmuk.[Title],
dmuk.[Initial],
dmuk.[Forename],
dmuk.[Surname],
dmuk.[Salutation],
dmuk.[Address 1],
dmuk.[Address 2],
dmuk.[Address 3],
dmuk.[Address 4],
dmuk.[Address 5],
dmuk.[Address 6],
dmuk.[PostCode],
ROW_NUMBER() OVER(PARTITION BY dmuk.[Output Code], dmuk.BatchNo ORDER BY newid()) as rn
FROM [dbo].[Direct_Marketing_UK] dmuk INNER JOIN
AttributionOutput ao ON dmuk.[Output Code] = ao.[Output Code]
AND dmuk.BatchNo = ao.BatchNo
AND dmuk.MonthandYear = ao.MonthandYear
)
SELECT URN,
[Output Code],
[BatchNo]
FROM CodeandBatch
WHERE rn <=
I can't see how a ROW_NUMBER() can help me to grab 25 percent of the rows from every combination of Output Code and batch number.
I suggest you look at NTILE for this.

T-SQL - Get last as-at date SUM(Quantity) was not negative

I am trying to find a way to get the last date by location and product a sum was positive. The only way i can think to do it is with a cursor, and if that's the case I may as well just do it in code. Before i go down that route, i was hoping someone may have a better idea?
Table:
Product, Date, Location, Quantity
The scenario is; I find the quantity by location and product at a particular date, if it is negative i need to get the sum and date when the group was last positive.
select
Product,
Location,
SUM(Quantity) Qty,
SUM(Value) Value
from
ProductTransactions PT
where
Date <= #AsAtDate
group by
Product,
Location
i am looking for the last date where the sum of the transactions previous to and including it are positive
Based on your revised question and your comment, here another solution I hope answers your question.
select Product, Location, max(Date) as Date
from (
select a.Product, a.Location, a.Date from ProductTransactions as a
join ProductTransactions as b
on a.Product = b.Product and a.Location = b.Location
where b.Date <= a.Date
group by a.Product, a.Location, a.Date
having sum(b.Value) >= 0
) as T
group by Product, Location
The subquery (table T) produces a list of {product, location, date} rows for which the sum of the values prior (and inclusive) is positive. From that set, we select the last date for each {product, location} pair.
This can be done in a set based way using windowed aggregates in order to construct the running total. Depending on the number of rows in the table this could be a bit slow but you can't really limit the time range going backwards as the last positive date is an unknown quantity.
I've used a CTE for convenience to construct the aggregated data set but converting that to a temp table should be faster. (CTEs get executed each time they are called whereas a temp table will only execute once.)
The basic theory is to construct the running totals for all of the previous days using the OVER clause to partition and order the SUM aggregates. This data set is then used and filtered to the expected date. When a row in that table has a quantity less than zero it is joined back to the aggregate data set for all previous days for that product and location where the quantity was greater than zero.
Since this may return multiple positive date rows the ROW_NUMBER() function is used to order the rows based on the date of the positive quantity day. This is done in descending order so that row number 1 is the most recent positive day. It isn't possible to use a simple MIN() here because the MIN([Date]) may not correspond to the MIN(Quantity).
WITH x AS (
SELECT [Date],
Product,
[Location],
SUM(Quantity) OVER (PARTITION BY Product, [Location] ORDER BY [Date] ASC) AS Quantity,
SUM([Value]) OVER(PARTITION BY Product, [Location] ORDER BY [Date] ASC) AS [Value]
FROM ProductTransactions
WHERE [Date] <= #AsAtDate
)
SELECT [Date], Product, [Location], Quantity, [Value], Positive_date, Positive_date_quantity
FROM (
SELECT x1.[Date], x1.Product, x1.[Location], x1.Quantity, x1.[Value],
x2.[Date] AS Positive_date, x2.[Quantity] AS Positive_date_quantity,
ROW_NUMBER() OVER (PARTITION BY x1.Product, x1.[Location] ORDER BY x2.[Date] DESC) AS Positive_date_row
FROM x AS x1
LEFT JOIN x AS x2 ON x1.Product=x2.Product AND x1.[Location]=x2.[Location]
AND x2.[Date]<x1.[Date] AND x1.Quantity<0 AND x2.Quantity>0
WHERE x1.[Date] = #AsAtDate
) AS y
WHERE Positive_date_row=1
Do you mean that you want to get the last date of positive quantity come to positive in group?
For example, If you are using SQL Server 2012+:
In following scenario, when the date going to 01/03/2017 the summary of quantity come to 1(-10+5+6).
Is it possible the quantity of following date come to negative again?
;WITH tb(Product, Location,[Date],Quantity) AS(
SELECT 'A','B',CONVERT(DATETIME,'01/01/2017'),-10 UNION ALL
SELECT 'A','B','01/02/2017',5 UNION ALL
SELECT 'A','B','01/03/2017',6 UNION ALL
SELECT 'A','B','01/04/2017',2
)
SELECT t.Product,t.Location,SUM(t.Quantity) AS Qty,MIN(CASE WHEN t.CurrentSum>0 THEN t.Date ELSE NULL END ) AS LastPositiveDate
FROM (
SELECT *,SUM(tb.Quantity)OVER(ORDER BY [Date]) AS CurrentSum FROM tb
) AS t GROUP BY t.Product,t.Location
Product Location Qty LastPositiveDate
------- -------- ----------- -----------------------
A B 3 2017-01-03 00:00:00.000

Adding a total column PIVOT TABLE

Here is my code guys i want to be able to return an total column of 2016,2015,2014,2013 but when i do this
Sum([2016]+[2015]+[2014]+[2013]) as Revenue like this its returns NULLS.
or this
Sum(2016+2015+2014+2013) as Revenue like this returns a different number than if you go take a calculator and add the numbers in 2013 2014 2015 and 2016
The numbers doesn't add up in the total column.
SELECT AirCarrierName,
SUM([2016]) AS [2016],
SUM([2015]) AS [2015],
SUM([2014]) AS [2014],
SUM([2013]) AS [2013]
FROM Sum_Orders
PIVOT
(
SUM(Sum_Orders.Sum_SellPrice)
FOR Sum_Orders.OrderperiodYear IN ([2016],[2015],[2014],[2013])
)AS pvt
WHERE OrderStatus IN ('INVOICED','OPEN') AND AirCarrierName
NOT LIKE 'NULL'
and AirCarrierName = 'CATHAY PACIFIC AIRWAYS LTD.'
GROUP BY AirCarrierName
Order by [2016] desc
this code returns the following
when i add up the lines for creating the total column this is what i get,
instead of having a nice sum of 2013 to 2016 in total column
Sum([2016]+[2015]+[2014]+[2013]) as total
this is the query with the total column included which is returning Nulls
SELECT AirCarrierName,
SUM(Sum_BuyPrice) AS Buy_price,
SUM(Sum_SellerMargin) AS Margin, sum(Sum_GrossWeightkg/1000)as Kilos_total,
SUM([2016]) AS [2016],
SUM([2015]) AS [2015], SUM([2014]) AS [2014], SUM([2013])
AS [2013],
SUM([2016]+[2015]+[2014]+[2013])as [total]
FROM Sum_Orders
PIVOT
(
SUM(Sum_Orders.Sum_SellPrice)
FOR Sum_Orders.OrderperiodYear IN ([2016],[2015],[2014],[2013])
)AS pvt
WHERE OrderStatus IN ('INVOICED','OPEN') AND AirCarrierName NOT LIKE 'NULL'
GROUP BY AirCarrierName

Can I order rows in my pivot table by aggregate value in sql server

Hi I'm studying for the querying Microsoft server certification hence the use of the TSQL2012 server datasource. This is not homework but just exploration of the topics.
The big picture is I'm trying to have a pivot table with the sales per customer(companyname) broken down by order year. however I am trying to order the rows of the the pivot table so that the company with the highest sales over the all years (three in this case) is at the top of the list.
WITH basedata as(
select
companyname as Company
,Year(orderdate) as [Order Year]
,((unitprice*qty)*(1-discount)) AS Sales
from
sales.Orders as o
right join Sales.MyCustomers as n
ON o.custid = n.custid
join Sales.OrderDetails as d
ON d.orderid = o.orderid
)SELECT
Company, [2006],[2007],[2008]
FROM
basedata
pivot
(sum(Sales) FOR [Order Year] in ([2006],[2007],[2008]))
as PVT
Order by
sum(Sales);
I get the error below
Msg 207, Level 16, State 1, Line 18
Invalid column name 'Sales'.
The way to order the pivot table so that the top row of the pivot table had the company with the highest sales for the three years combined while also taking into consideration fact that some companies could have had a null value for sales (ISNULL function replaced a null value with 0) was to
ORDER BY ISNULL(pvt.[2006], 0) + ISNULL(pvt.[2007], 0)
+ ISNULL(pvt.[2008], 0) DESC;

Roll up and Cube operator in access (Summary Queries)

Are there any equivalents to the Rollup and Cube operators in Access? If not, how can I write subtotal and grand total (summary data) queries in Access?
I have written :
SELECT a,b FROM dumy
UNION ALL select a,sum(b) from dumy
group by a ;
The output is like the image below, or something similar to that,
But the expected result is this:
You can use Crosstab queries. This will produce one row:
TRANSFORM Count(b.ID) AS [Count]
SELECT "BASE" AS SomeName, Count(b.ID) AS Total
FROM ATable AS b
WHERE Something='Text'
GROUP BY "BASE"
PIVOT AFieldName;
It just requires sorting.
Select T.Total
, T.a
, T.b
From (
SELECT '' as Label
, a
,b
FROM dumy
UNION ALL
select 'Total' as Label
, a
,sum(b)
from dumy
group by a
) as T
Order By T.a, T.Total;

Resources