Bundle with order numbers - sql

I am trying to generate a report where I want to get total sale values and quantities .
explanation:
When customers some products they get free gift , so items are two types standard and free gift . When they buy standard item they get free gift but not all the customers are eligible for it. In database they are hard coded as standard =0 and free gift as =1.
Aim 1: I would like to get only number of orders with free gifts and the total of that orders.
Aim 2: I want to count each count of free gift to find out top 10.
All the fields are in brackets.
below is simple example .
Hope this make sense. Thank you .
Results :
my script:
select
oh.[order date],
oh.[order guid],
[Item No_] as SKU
,ti.[Description],
ol.[quantity],
ol.Amount,
[EMS Available Quantity] as Stock_Qty,
(case when [Product Type]=0 then 'Standard'
when[Product Type]=1 then 'free_gift'
end) as Product_Type
from [Big$Item] TI
Inner join [Big$Inventory] I
ON I.[Item No_] = TI.[No_]
inner join [Big$Order Line] ol
on ti.[No_]=ol.[No_]
inner join [Big$Order header]oh
on oh.[order guid]=ol.[order guid]
where [Product Type] in ('0','1')
and oh.[order date] between'2017-06-12' and '2017-06-18'
order by [order date] asc

finally i have a solution - maybe not the most beautiful one - but it is working:
i have also added the create statement and the testdata insert - you can also reproduce it with this test link: http://rextester.com/JRV11837
The first Select just returns all orderguid which have at least one free gift.
The second Select i used to join includes the total amount of each order. As i use an INNER JOIN the final result will be just orders which include freegifts.
Finally i just group the resultset by the description of the freegift.
CREATE TABLE mygifttable
( Date datetime
,orderguid varchar(10)
,description varchar(55)
,sku int
,amount decimal)
;
INSERT INTO mygifttable VALUES
('2017-06-01', '1234', 'Sony Speakers' , 25, 100),
('2017-06-01', '1234', 'Sony Tv' , 23, 250),
('2017-06-01', '1234', 'Tv stand' , 11, 0),
('2017-06-01', '1235', 'Samsung Speakers', 28, 150),
('2017-06-01', '1235', 'Samsung Tv' , 26, 350),
('2017-06-01', '1235', 'Wall mount' , 10, 0),
('2017-06-01', '1236', 'Sony Speakers' , 25, 100),
('2017-06-01', '1236', 'Sony Tv' , 23, 250),
('2017-06-01', '1236', 'Tv stand' , 11, 0),
('2017-06-01', '1237', 'Apple mobiles' , 29, 900),
('2017-06-01', '1237', 'Apple cable' , 30, 800)
;
SELECT freegifttable.description
,SUM(freegifttable.freegift) as Free_Gifts
,SUM(totalamount.orderamount) as Total_Orderamount
FROM (
SELECT description
,orderguid
,SUM(IIF(amount = 0, 1,0)) as freegift
FROM mygifttable
GROUP BY description, orderguid
HAVING SUM(IIF(amount = 0, 1,0)) != 0
) freegifttable
INNER JOIN
(
SELECT orderguid
,SUM(amount) as orderamount
FROM mygifttable
GROUP BY orderguid
) totalamount
ON totalamount.orderguid = freegifttable.orderguid
GROUP BY freegifttable.description
;

Related

Ranking at Multiple Levels on SQL Server

I've read a few ways of doing this, but it does not seem to work for me. I'm trying to pull data that has a Category, Itemcode, and Sales. I'm summing this up for a period of time so that my basic query looks like this:
select
Category
, Itemcode
, sum(Sales)
, rank() over (partition by Category order by sum(Sales) desc) as ItemRank
from
Sales
group by
Category, Itemcode
When I do that, my data looks like this:
What I would like to do is to add another rank that would show the rank of the Category as a whole.
Something like this:
What would the query look like with that added in? I've tried several things, but I can't seem to get it to work.
Taking a guess here, but I gather you want to rank based on the TotalSales? If so, you can join to a subquery to do the aggregation, then use that in another rank column:
declare #Sales table (Category varchar(25), ItemCode int, Sales int)
insert into #Sales
values
('Category A', 123, 100),
('Category A', 234, 125),
('Category A', 345, 97),
('Category B', 456, 354),
('Category B', 567, 85),
('Category B', 678, 112)
select
s.Category
, Itemcode
, sum(s.Sales)
, rank() over (partition by s.Category order by sum(Sales) desc) as ItemRank
, dense_rank() over (order by sum(TotalSales) desc) as CategoryRank
from #Sales s
join ( select Category, sum(Sales) as TotalSales
from #Sales
group by Category
) d
on s.Category = d.Category
group by s.Category, Itemcode

Return latest values for each month filling empty values

In SQL Server 2017 I have a table that looks like this https://i.stack.imgur.com/Ry106.png and I would like to get the amount of members at the end of each month, filling out the blank months with the data from the previous month.
So having this table
Create table #tempCenters (
OperationId int identity (1,1) primary key,
CenterId int,
members int,
Change_date date,
Address varchar(100), --non relevant
Sales float --non relevant
)
with this data
INSERT INTO #tempCenters VALUES
(1, 100, '2020-02-20', 'non relevant column', 135135),
(1, 110, '2020-04-15', 'non relevant column', 231635),
(1, 130, '2020-04-25', 'non relevant column', 3565432),
(1, 180, '2020-09-01', 'non relevant column', 231651),
(2, 200, '2020-01-20', 'non relevant column', 321365),
(2, 106, '2020-03-20', 'non relevant column', 34534),
(2, 135, '2020-06-25', 'non relevant column', 3224),
(2, 154, '2020-06-20', 'non relevant column', 2453453)
I am expecting this result
CenterId, Members, EOM_Date
1, 100, '2020-2-28'
1, 100, '2020-3-30'
1, 130, '2020-4-31'
1, 130, '2020-5-30'
1, 130, '2020-6-31'
1, 130, '2020-7-31'
1, 130, '2020-8-30'
1, 180, '2020-9-31'
2, 200, '2020-1-31'
2, 200, '2020-2-28'
2, 106, '2020-3-31'
2, 106, '2020-4-30'
2, 106, '2020-5-31'
2, 135, '2020-6-30'
And this is what I´ve got so far
SELECT
t.centerId,
EOMONTH(t.Change_date) as endOfMonthDate,
t.members
FROM #tempCenters t
RIGHT JOIN (
SELECT
S.CenterId,
Year(S.Change_date) as dateYear,
Month(S.Change_date) as dateMonth,
Max(s.OperationId) as id
FROM #tempCenters S
GROUP BY CenterId, Year(Change_date), Month(Change_date)
) A
ON A.id = t.OperationId
which returns the values per month, but not fill the blank ones.
First I get start date (min date) and finish date (max date) for each CenterId. Then I generate all end of months from start date to finish date for each CenterId. Finally I join my subuqery (cte) with your table (on cte.CenterId = tc.CenterId AND cte.EOM_Date >= tc.Change_date) and get last (previous or same date) members value for each date (end of month).
WITH cte AS (SELECT CenterId, EOMONTH(MIN(Change_date)) AS EOM_Date, EOMONTH(MAX(Change_date)) AS finish
FROM #tempCenters
GROUP BY CenterId
UNION ALL
SELECT CenterId, EOMONTH(DATEADD(MONTH, 1, EOM_Date)), finish
FROM cte
WHERE EOM_Date < finish)
SELECT DISTINCT cte.CenterId,
FIRST_VALUE(Members) OVER(PARTITION BY cte.CenterId, cte.EOM_Date ORDER BY tc.Change_date DESC) AS Members,
cte.EOM_Date
FROM cte
LEFT JOIN #tempCenters tc ON cte.CenterId = tc.CenterId AND cte.EOM_Date >= tc.Change_date
ORDER BY CenterId, EOM_Date;
I know it looks cumbersome and I'm sure there is a more elegant solution, but still you can use a combination of subqueries with union all and outer apply to get the desired result.
Select t.CenterId, Coalesce(t.members, tt.members), t.Change_date
From (
Select CenterId, Max(members) As members, Change_date
From
(Select t.CenterId, t.members, EOMONTH(t.Change_date) As Change_date
From #tempCenters As t Inner Join
(Select CenterId, Max(Change_date) As Change_date
From #tempCenters
Group by CenterId, Year(Change_date), Month(Change_date)
) As tt On (t.CenterId=tt.CenterId And
t.Change_date=tt.Change_date)
Union All
Select t.CenterId, Null As member, t.Change_date
From (
Select tt.CenterId, EOMONTH(datefromparts(tt.[YEAR], t.[MONTH], '1')) As Change_date,
Min_Change_date, Max_Change_date
From (Select [value] as [Month] From OPENJSON('[1,2,3,4,5,6,7,8,9,10,11,12]')) As t,
(Select CenterId, Year(Change_date) As [YEAR],
Min(Change_date) As Min_Change_date, Max(Change_date) As Max_Change_date
From #tempCenters Group by CenterId, Year(Change_date)) As tt) As t
Where Change_date Between Min_Change_date And Max_Change_date) As t
Group by CenterId, Change_date) As t Outer Apply
(Select members
From #tempCenters
Where CenterId=t.CenterId And
Change_date = (Select Max(Change_date)
From #tempCenters Where CenterId=t.CenterId And Change_date<t.Change_date Group by CenterId)) As tt
Order by t.CenterId, t.Change_date

I would like to display current month, year to date and previous year to date on ssrs

Data Presentation
Would like to calculate year to date and previous year to date current month on sql view so that to simply data presentation on ssrs to make it run faster. Is there a way to write a view which can perform this ?
Ignoring the fact that I think you have some errors in your Previous YTD summary numbers..
I recreated the data as per your example
CREATE TABLE #t (TransDate date, Customer varchar(30), Amount float)
INSERT INTO #t VALUES
('2020-09-21', 'Customer 1', 200),
('2020-09-22', 'Customer 2', 300),
('2020-08-03', 'Customer 2', 450),
('2020-08-04', 'Customer 1', 1200),
('2019-09-14', 'Customer 1', 859),
('2019-02-05', 'Customer 2', 230),
('2019-07-26', 'Customer 2', 910),
('2019-11-17', 'Customer 1', 820)
Then the following statement will produce what you need. It is NOT the most elegant way of doing this but it will convert to a view easily and was all I could come up with in the time I had.
SELECT
m.Customer
, m.MTD as [Current Month]
, y.YTD as [Current YTD]
, p.YTD as [Previous YTD]
FROM (
SELECT Customer, Yr = Year(TransDate), Mn = MONTH(TransDate), MTD = SUM(Amount) FROM #t t WHERE MONTH(TransDate) = MONTH(GetDate()) and YEAR(TransDate) = YEAR(GetDate())
GROUP by Customer, YEAR(TransDate), MONTH(TransDate)
) m
JOIN (SELECT Customer, Yr = YEAR(TransDate), YTD = SUM(Amount) FROM #t t GROUP by Customer, YEAR(TransDate)) y on m.Customer =y.Customer and m.Yr = y.Yr
JOIN (SELECT Customer, Yr = YEAR(TransDate), YTD = SUM(Amount) FROM #t t GROUP by Customer, YEAR(TransDate)) p on y.Customer =p.Customer and y.Yr = p.Yr + 1
This gives the following results (which don;t match your example but I think your sample is incorrect)

How to convert table rows data to a pivot table in SQL Server

I have a table as below
DECLARE #Territory_Month TABLE
(
Territory VARCHAR(20),
[Order Status] VARCHAR(20),
[count Order Number] INT,
[sum Dollar Revenue] FLOAT
);
INSERT INTO #Territory_Month (Territory, [Order Status], [count Order Number], [sum Dollar Revenue])
VALUES ('BENELUX', 'RELEASED', 108, 20363879.11),
('CENTRAL EUROPE', 'RELEASED', 615, 11502633.14),
('EAST EUROPE', 'RELEASED', 292, 4689655.19),
('FRANCE', 'RELEASED', 228, 5333825.69),
('IBERIA', 'RELEASED', 82, 1985003.46),
('ITALY & ISRAEL', 'RELEASED', 211, 3844900.74),
('META', 'RELEASED', 173, 3478765.18),
('NORDICS', 'RELEASED', 132, 4017755.1252),
('SEE', 'RELEASED', 326, 2211346.28),
('UKI', 'RELEASED', 124, 17541413.6),
('BENELUX', 'UNRELEASED', 33, 505935.16),
('CENTRAL EUROPE', 'UNRELEASED', 111, 597457.364505),
('EAST EUROPE', 'UNRELEASED', 96, 2411721.25),
('FRANCE', 'UNRELEASED', 41, 466737.3675),
('IBERIA', 'UNRELEASED', 20, 112696.37),
('ITALY & ISRAEL', 'UNRELEASED', 129, 928122.01),
('META', 'UNRELEASED', 156, 771615.44),
('NORDICS', 'UNRELEASED', 34, 778853.82),
('SEE', 'UNRELEASED', 81, 260567.31),
('UKI', 'UNRELEASED', 115, 6335067.356471);
I want to create a pivot table based on this row data. The result should look as below:
Which means the sum of order number and dollar revenue split by order status for each territory.
I tried to use pivot twice, one for sum of order number and one for dollar revenue but it looks like i can't use the same column in more than a pivot
SELECT
Territory, [RELEASED], [UNRELEASED]
FROM
#Territory_Month
PIVOT
(SUM([count Order Number])
FOR [Order Status] IN ([RELEASED], [UNRELEASED])) piv1
PIVOT
(SUM([sum Dollar Revenue])
FOR [Order Status] IN ([RELEASED], [UNRELEASED])) piv2
ORDER BY
Territory
Any suggestions please ? Thank you.
Your image doesn't work -- another reason why text tables are so helpful.
But I think you want something like this:
select territory,
sum(case when status = 'RELEASED' then 1 else 0 end) as num_released,
sum(case when status = 'RELEASED' then rev else 0 end) as rev_released,
sum(case when status = 'UNRELEASED' then 1 else 0 end) as num_unreleased,
sum(case when status = 'UNRELEASED' then rev else 0 end) as rev_unreleased
from #Territory_Month tm
group by territory;
Here is a db<>fiddle.
Notice that I changed the column names so they don't have to be escaped. That makes it easier to write and read queries.
By changing the column name & value you can use multiple columns with Pivot like below
Try This
DECLARE #Territory_Month TABLE
(Territory varchar(20), [Order Status] varchar(20), [count Order Number] int,[sum Dollar Revenue] float);
INSERT INTO #Territory_Month
(Territory, [Order Status], [count Order Number], [sum Dollar Revenue])
VALUES
('BENELUX','RELEASED',108,20363879.11),
('CENTRAL EUROPE','RELEASED',615,11502633.14),
('EAST EUROPE','RELEASED',292,4689655.19),
('FRANCE','RELEASED',228,5333825.69),
('IBERIA','RELEASED',82,1985003.46),
('ITALY & ISRAEL','RELEASED',211,3844900.74),
('META','RELEASED',173,3478765.18),
('NORDICS','RELEASED',132,4017755.1252),
('SEE','RELEASED',326,2211346.28),
('UKI','RELEASED',124,17541413.6),
('BENELUX','UNRELEASED',33,505935.16),
('CENTRAL EUROPE','UNRELEASED',111,597457.364505),
('EAST EUROPE','UNRELEASED',96,2411721.25),
('FRANCE','UNRELEASED',41,466737.3675),
('IBERIA','UNRELEASED',20,112696.37),
('ITALY & ISRAEL','UNRELEASED',129,928122.01),
('META','UNRELEASED',156,771615.44),
('NORDICS','UNRELEASED',34,778853.82),
('SEE','UNRELEASED',81,260567.31),
('UKI','UNRELEASED',115,6335067.356471);
Select * From
(
SELECT Territory, [Order Status] OrderStatus1, [Order Status] + '2' OrderStatus2, [count Order Number], [sum Dollar Revenue]
FROM #Territory_Month ) as tbl
PIVOT ( SUM([count Order Number]) FOR [OrderStatus1] in ([RELEASED],[UNRELEASED])) piv1
PIVOT ( SUM([sum Dollar Revenue]) FOR [OrderStatus2] in ([RELEASED2],[UNRELEASED2])) piv2
ORDER BY Territory

Multi-aggregate, Multi-Filter, Single Table SQL

The following simulated table contains order details where cust_nbr represents the order number. I'm trying to find where if an order contains an item_nbr 90000, I need to know if the price for 90000 is greater than the sum of the other items plus tax. I have hundreds of thousands of records in this table. I am using Teradata.
CREATE TABLE Line_Item_Details_Tbl (
cust_nbr INT,
trn_dt DATE,
str_typ VARCHAR(6),
trn_nbr INT,
item_nbr INT,
price DECIMAL(6,2),
tax DECIMAL(6,2)
);
Sample data:
INSERT INTO Line_Item_Details_Tbl VALUES
(5551, '12/22/2011', 'store', 215, 12345, 10.00, 1.25);
INSERT INTO Line_Item_Details_Tbl VALUES
(5551, '12/22/2011', 'store', 215, 65715, 6.25, 0.75);
INSERT INTO Line_Item_Details_Tbl VALUES
(5551, '12/22/2011', 'store', 215, 90000, 40.00, 0);
INSERT INTO Line_Item_Details_Tbl VALUES
(6875, '12/10/2011', 'online', 856, 72345, 8.50, 1.00);
INSERT INTO Line_Item_Details_Tbl VALUES
(6875, '12/10/2011', 'online', 856, 65715, 6.25, 0.75);
INSERT INTO Line_Item_Details_Tbl VALUES
(3500, '12/12/2011', 'store', 402, 54123, 45.00, 4.00);
INSERT INTO Line_Item_Details_Tbl VALUES
(3500, '12/12/2011', 'store', 402, 90000, 20.00, 0);
INSERT INTO Line_Item_Details_Tbl VALUES
The query should do the following:
Select cust_nbr, trn_dt, trn_nbr, sum(price + tax) as purchase
For a cust_nbr with str_typ = 'store' AND contains an item_nbr = 90000,
aggregate price + tax for all items related to cust_nbr except item_nbr 90000
So, preliminary result should be:
cust_nbr : trn_dt : trn_nbr : purchase
5551 12/22/2011 215 $18.25
3500 12/12/2011 402 $49.00
Then, for each record in the preliminary results, I need to subtract the price of item_nbr 90000 from the purchase and return results only if the purchase is less than
the price of item_nbr 90000 as net_cb
So, my ending result should be:
cust_nbr trn_dt trn_nbr net_cb
5551 12/22/2011 215 ($21.75)
Use a sub-query to identify the transaction you want, then use CASE to determin which records contribute to you aggregates or not.
SELECT
transactions.cust_nbr,
transactions.trn_dt,
transactions.trn_nbr,
sum(price + tax) AS total,
sum(CASE WHEN item_nbr = 9000 THEN 0 ELSE price + tax END) AS total_less_9000
FROM
(
SELECT
cust_nbr, trn_dt, trn_nbr
FROM
yourTable
WHERE
str_typ = 'store'
AND item_nbr = 90000
GROUP BY
cust_nbr, trn_dt, trn_nbr
)
AS transactions
INNER JOIN
yourTable
ON transactions.cust_nbr = yourTable.cust_nbr
AND transactions.trn_dt = yourTable.trn_dt
AND transactions.trn_nbr = yourTable.trn_nbr
GROUP BY
transactions.cust_nbr, transactions.trn_dt, transactions.trn_nbr
Or simply use the HAVING clause to determine which transactions to include.
SELECT
cust_nbr,
trn_dt,
trn_nbr,
sum(price + tax) AS total,
sum(CASE WHEN item_nbr = 9000 THEN 0 ELSE price + tax END) AS total_less_9000
FROM
yourTable
GROUP BY
cust_nbr,
trn_dt,
trn_nbr
HAVING
MAX(CASE WHEN item_nbr = 9000 THEN 1 ELSE 0 END) = 1
Or...
HAVING
EXISTS (SELECT * FROM yourTable AS lookup
WHERE cust_nbr = yourTable.cust_nbr
AND trn_dt = yourTable.trn_dt
AND trn_nbr = yourTable.trn_nbr
AND item_nbr = 9000
)
I've tested in on SQL Server 2005 so please do not downvote if it doesn't work at all, just let me know and I will delete my answer :-). I'm just trying to help.
Treat this as your sample data (CTE in SQL Server 2005):
;with ord_det (cust_nbr, trn_dt, str_typ, trn_nbr, item_nbr, price, tax) as (
select 5551, convert(datetime, '12/22/2011', 101), 'store', 215, 12345, 10.00, 1.25 union all
select 5551, convert(datetime, '12/22/2011', 101), 'store', 215, 65715, 6.25, 0.75 union all
select 5551, convert(datetime, '12/22/2011', 101), 'store', 215, 90000, 40.00, null union all
select 6875, convert(datetime, '12/10/2011', 101), 'online', 856, 72345, 8.50, 1.00 union all
select 6875, convert(datetime, '12/10/2011', 101), 'online', 856, 65715, 6.25, 0.75 union all
select 3500, convert(datetime, '12/12/2011', 101), 'store', 402, 54123, 45.00, 4.00 union all
select 3500, convert(datetime, '12/12/2011', 101), 'store', 402, 90000, 20.00, null
)
Final query (I assumed that your table name is ord_det, if it's not just use proper name):
select t.cust_nbr, t.trn_dt, t.trn_nbr, price - purchase as net_cb from (
select cust_nbr, trn_dt, trn_nbr, sum(price + coalesce(tax, 0)) as purchase
from ord_det o
where item_nbr <> 90000 and str_typ = 'store'
group by cust_nbr, trn_dt, trn_nbr
) t
inner join (
select cust_nbr, trn_dt, trn_nbr, price + coalesce(tax, 0) as price
from ord_det o
where item_nbr = 90000 and str_typ = 'store'
) t1 on t.cust_nbr = t1.cust_nbr
where purchase < price
Result:
cust_nbr trn_dt trn_nbr net_cb
5551 2011-12-22 00:00:00.000 215 21.75