sum pivot value in sql server 2008 - sql-server

Select * From
(SELECT convert(varchar,SUM(distance))
As total_distance, DAY(start_time) Days
FROM t1
Where id=6314
And start_time
Between '2018-02-01 18:30:00'
And '2018-02-09 18:00:00'
GROUP BY DAY(start_time)
) d
pivot
(Max(total_distance)
For Days in ([3],[4],[5],[6],[7],[8],[9])
) piv;
results-
3 4 5 6 7 8 9
0 0 50.2 44.32 42.34 43.38 41.32
i want a sum column for these values along with this result like ;-
sum 3 4 5 6 7 8 9
221.56 0 0 50.2 44.32 42.34 43.38 41.32

add the following to your result set of the query: the CROSS APPLY part.
;WITH t ([3] ,[4] ,[5] ,[6] , [7], [8] ,[9]) as
(
SELECT 0 , 0 , 50.2 , 44.32 , 42.34 , 43.38 , 41.32
)
SELECT *
FROM t
CROSS APPLY
(SELECT SUM(x.Val)
FROM
(
VALUES ([3]),([4]),([5]),([6]),([7]),([8]),([9])
) X (VAL)
) P(SVal)
and here is the query with your input:
;WITH Pvt as
(
select * from
(SELECT convert(varchar,SUM(distance)) as total_distance, DAY(start_time) Days
FROM t1
where id=6314 and start_time between '2018-02-01 18:30:00' and '2018-02-09 18:00:00'
GROUP BY DAY(start_time)
) d
pivot
(max(total_distance)
for Days in ([3],[4],[5],[6],[7],[8],[9])
) piv
)
SELECT *
FROM Pvt
CROSS APPLY
(SELECT SUM(x.Val)
FROM
(
VALUES ([3]),([4]),([5]),([6]),([7]),([8]),([9])
) X (VAL)
) P(SVal)

Related

Pivot table missing data in sum in SQL Server

I have the following reference table:
CompanyId ProductType ProductCount ProductBought
3 1 12 12
3 2 5 5
3 4 5 5
Then I'm pivoting the table by ProductType:
SELECT
CompanyId,
SUM(ProductBought) AS ProductBought
SUM(ISNULL([1], 0)) AS [1],
SUM(ISNULL([2], 0)) AS [2],
SUM(ISNULL([3], 0)) AS [3],
SUM(ISNULL([4], 0)) AS [4]
FROM (
SELECT * FROM #ReferenceTable
) AS a
PIVOT (
SUM([ProductCount]) FOR ProductType IN ([1], [2], [3], [4])
) as pvt
GROUP BY pvt.CompanyId
This gives the following result:
CompanyId ProductBought 1 2 3 4
3 17 12 5 0 5
I expect the ProductBought value to be 22, so in the pivot, five are going missing.
How can I achieve the full count of ProductBought with the pivot table?
In your query amounts are grouping up based on ProductBrought column. Since for both ProductType 2,4 ProductBrought values are 5 . The data gets grouped up on one single 5 . Just separate them with a simple Row Id column and try.
SELECT * INTO #TEMP FROM
(
SELECT 3 companyId, 1 ProductType,12 ProductCount,12 ProductBought
UNION ALL
SELECT 3, 2,5 ,5 UNION ALL
SELECT 3, 4,5 ,5
)
AS A
Query
SELECT SUM(ProductBought)ProductBought,SUM([1]) [1],SUM([2])[2],SUM([3])[3],SUM([4])[4]
FROM (
SELECT ROW_NUMBER()OVER(PARTITION BY companyId ORDER BY (SELECT 1 )DESC)RN,* FROM #TEMP
) AS A
PIVOT ( SUM( ProductCOUNT ) FOR ProductType IN([1],[2],[3],[4])
)AS B
GROUP BY COMPANYID
Try This
;WITH CTE(CompanyId, ProductType, ProductCount, ProductBought)
AS
(
SELECT 3, 1,12,12 UNION ALL
SELECT 3, 2,5 ,5 UNION ALL
SELECT 3, 4,5 ,5
)
SELECT CompanyId,
ProductBought,
ISNULL(SUM([1]),0) AS [1],
ISNULL(SUM([2]),0) AS [2],
ISNULL(SUM([3]),0) AS [3],
ISNULL(SUM([4]),0) AS [4]
FROM
(
SELECT CompanyId,
ProductType,
ProductCount,
SUM(ProductBought)OVER(ORDER BY CompanyId) AS ProductBought
FROM CTE
)AS SRC
PIVOT
(
SUM(ProductCount) FOR ProductType IN ([1],[2],[3],[4])
)
AS PVT
GROUP BY CompanyId,
ProductBought
Result
CompanyId ProductBought 1 2 3 4
------------------------------------------------
3 22 12 5 0 5
You can sum separately and join with pivot results as below.
SELECT MainTable.CompanyId, MainTable.ProductBought, PivotTable.[1], PivotTable.[2],
PivotTable.[3], PivotTable.[4]
FROM
(
SELECT ReferenceTable.CompanyId, SUM(ProductBought) AS ProductBought FROM
ReferenceTable
GROUP BY CompanyId
) MainTable
INNER JOIN
(
SELECT
CompanyId,
SUM(ISNULL([1], 0)) AS [1],
SUM(ISNULL([2], 0)) AS [2],
SUM(ISNULL([3], 0)) AS [3],
SUM(ISNULL([4], 0)) AS [4]
FROM (
SELECT * FROM dbo.ReferenceTable
) AS a
PIVOT (
SUM([ProductCount]) FOR ProductType IN ([1], [2], [3], [4])
) as pvt
GROUP BY pvt.CompanyId
) PivotTable
ON PivotTable.CompanyId = MainTable.CompanyId

SQL Server sum query every 06:30 AM

Really need some help: I have a SQL Server table like this :
And I want to do a query to count value everyday start from 06:30 today until 06:29 tomorrow.
The problem is, the value does not start from 0 every 06:30.
I need query like this: Select maximum value per code first, ex :
(code : value)
M12 : 108,
M77 : 26
then the M77 value not start from 06:30.
I need to do : 26 - 12 (value before 06:30:00), so the M77 now is 14.
Finally sum the M77 and M12 = 14 + 108 = 122.
My expected output only for total value per date.
Based on my DB (image), the total value will be 26 - 12 =14.
26 is the latest value.
12 is value before 06:30
How to do it in SQL Server? Please help me
if i do understand you requirement correctly.
The query explanation are in code comments
; with
-- for getting the max value by code, rn = 1 is the max value
cte1 as
(
select *, rn = row_number() over (partition by code order by value desc)
from sample_table
),
-- for getting rows before 6:30, rn = 1 is the last record before 6:30
cte2 as
(
select *, rn = row_number() over (partition by code order by [date] desc)
from sample_table
where convert(time, [date]) < '06:30'
)
select total = sum(case when convert(time, c1.[date]) < '06:30'
then c1.value
else c1.value - c2.value
end)
from cte1 c1
left join cte2 c2 on c1.code = c2.code
and c1.rn = c2.rn
where c1.rn = 1
Try this
SELECT SUM([output]) AS [output]
FROM (
SELECT [latest]
,[before]
,(CASE WHEN [latest] = [before] THEN [latest]
ELSE [latest] - [before] END) AS [output]
FROM (
SELECT [code]
,MAX([value]) AS [latest]
,(SELECT MAX([value])
FROM [table]
WHERE [date] &lt CONVERT(datetime, CONVERT(varchar(10), CONVERT(date, [date])) + ' 06:30:00:000')
AND [code] = [t].[code]
GROUP BY [code]) AS [before]
FROM [table] AS [t]
GROUP BY [code]) AS [src]
) AS [rpt]
Try this puzzle:
CREATE TABLE TestTable
(
[date] datetime,
value int,
code varchar(10)
)
GO
INSERT INTO [dbo].[TestTable]
([date]
,[value]
,[code])
VALUES
('2018-09-13 06:20:52.803'
,100
,'M12'),
('2018-09-13 06:21:52.803'
,102
,'M12')
, ('2018-09-13 06:22:52.803'
,104
,'M12')
, ('2018-09-13 06:23:52.803'
,106
,'M12')
, ('2018-09-13 06:24:52.803'
,108
,'M12')
, ('2018-09-13 06:25:52.803'
,2
,'M77')
, ('2018-09-13 06:29:14.803'
,4
,'M77')
, ('2018-09-13 06:29:16.803'
,6
,'M77')
, ('2018-09-13 06:29:18.803'
,8
,'M77')
, ('2018-09-13 06:29:45.803'
,10
,'M77')
, ('2018-09-13 06:29:55.803'
,12
,'M77')
, ('2018-09-13 06:30:18.803'
,14
,'M77')
, ('2018-09-13 06:31:18.803'
,26
,'M77')
;WITH RESULT AS (
SELECT
TT.code
, MaxValueThatday = max(maxval.MAXVALUE )
, MaxValueBefore630NextDay = max(MAXValBefore630.MAXVALUE)
, ResultSubstraction =
CASE WHEN max(maxval.MAXVALUE ) <> max(MAXValBefore630.MAXVALUE)
THEN max(maxval.MAXVALUE ) - max(MAXValBefore630.MAXVALUE)
ELSE max(maxval.MAXVALUE )
END
FROM [dbo].[TestTable] TT
OUTER APPLY(
SELECT max(VALUE) MAXVALUE
, code
FROM [dbo].[TestTable] aa
WHERE Aa.code = tt.code
group by code
)maxval
OUTER APPLY(
SELECT max(A.VALUE) MAXVALUE
, code
FROM [dbo].[TestTable] A
WHERE DATEPART(HOUR,[DATE]) <= 6 AND DATEPART(MINUTE,[DATE]) < 30
and A.code = tt.code
group by code
)MAXValBefore630
where ( [DATE] > DATEADD(MINUTE,390,CAST({ fn CURDATE()} AS DATETIME) ) ) --6:30 today
group by tt.code
)
SELECT SUM(ResultSubstraction)
FROM RESULT

Get the difference between top and last value in result set

My table looks something like
deal_id test_value run_date
820117648 1.2 2014-03-31
820117648 1.33 2014-04-30
820117648 1.33 2014-05-30
820117648 1.26 2014-06-30
820117648 1.11 2014-07-31
820117648 0.58 2014-09-30
820117648 1.64 2014-10-31
820117648 0.64 2014-11-28
820117648 3.65 2014-12-31
820117648 3.8 2015-03-11
820117649 0.64 2014-09-31
820117649 0.23 2014-10-31
820117649 0.64 2014-11-28
820117649 3.65 2014-12-31
820117649 3.8 2015-03-11
SELECT deal_id,test_value,run_date FROM ems.cdotests
WHERE run_date >= Dateadd(month, -4 Getdate())
I am trying to grab the last 4 run_date record from the whole set and then
I need to find the difference between the testValue on the first rundate of my select criteria and the last rundate i.e for deal_id 820117649 3.8 - 0.23 = 3.57 and for deal_id 820117648 it should be 3.8 -1.64 = 2.16
This is the large table with multiple deal id and several run_date associated with each dealid and may have data for the last 15 years or so
Any suggestion would be really helpfull
Try this solution. It will not be bound to particular deal_id.
DECLARE #t TABLE ( ID INT, V MONEY, D DATE )
INSERT INTO #t
VALUES ( 1, 1, '20140101' ),
( 1, 4, '20140102' ),
( 1, 2, '20140103' ),
( 1, 7, '20140104' ),
( 2, 5, '20140104' ),
( 2, 8, '20140110' ),
( 2, 11, '20140105' );
WITH cte
AS ( SELECT ID ,
D ,
V ,
MIN(D) OVER ( PARTITION BY ID ORDER BY D ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS Min ,
MAX(D) OVER ( PARTITION BY ID ORDER BY D ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS Max
FROM #t
)
SELECT c1.ID ,
c2.V - c1.V AS V
FROM cte c1
JOIN cte c2 ON c1.ID = c2.ID AND c1.D < c2.D
WHERE ( c1.D = c1.MIN OR c1.D = c1.MAX ) AND ( c2.D = c2.MIN OR c2.D = c2.MAX )
Output:
ID V
1 6.00
2 3.00
You have changed you question. For latest 6 month, add filter CTE above main CTE:
;WITH filter
AS ( SELECT ID ,
D ,
V ,
ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY D DESC ) AS RN
FROM #t
),
cte
AS ( SELECT ID ,
D ,
V ,
MIN(D) OVER ( PARTITION BY ID ORDER BY D ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS Min ,
MAX(D) OVER ( PARTITION BY ID ORDER BY D ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS Max
FROM filter
WHERE RN <= 6
)
SELECT c1.ID ,
c2.V - c1.V AS V
FROM cte c1
JOIN cte c2 ON c1.ID = c2.ID AND c1.D < c2.D
WHERE ( c1.D = c1.MIN OR c1.D = c1.MAX )
AND ( c2.D = c2.MIN OR c2.D = c2.MAX )
AND (c2.V - c1.V > 5)
You can use window functions
WITH C AS(
SELECT ROW_NUMBER() OVER (PARTITION BY deal_Id ORDER BY deal_Id) Rn
,deal_Id
,test_value
,run_date
FROM ems.cdotests
)
SELECT id1 deal_id, t2 - t1 diff
FROM (SELECT c1.deal_id id1
,c1.test_value t1
,c2.deal_id id2
, c2.test_value t2
FROM C c1
INNER JOIN C c2 ON c1.deal_id = c2.deal_id
WHERE c1.Rn = 1
AND c2.Rn = (SELECT TOP 1 MAX(Rn) FROM C GROUP BY deal_id)
) t
So late to answer, but a way is this:
;with t as (
select *,
row_number() over (partition by deal_id order by run_date desc) seq
from ems.cdotests
)
select
t1.deal_id, t1.run_date run_date1, t1.test_value test_value1,
t2.run_date run_date4, t2.test_value test_value4,
t1.test_value - t2.test_value diff
from t t1
join t t2
on t1.deal_id = t2.deal_id
where t1.seq = 1
and t2.seq = 4
-- as an extra condition of those should have at least 5 records:
and exists (select 1 from t ti where ti.deal_id = t1.deal_id and ti.seq > 5)
[SQL Fiddle]

SQL Server 2008 : TSQL, select same data for different times based on column value

I am using mssql 2008 R2,
i have below structure
create table #temp (
product int,
[order] int,
ord_qnty int
)
insert #temp
select 10 ,3,4
now, if ord_qnty is 4 , i want to select same product,order four times but in all four rows thevalue of ord_qnty should be 1 , i.e.
out put should be
Product order ord_qnty
10 3 1
10 3 1
10 3 1
10 3 1
If you have a numbers table, you can use that. If not, you can generate one:
;with Numbers(n) as (
select ROW_NUMBER() OVER (ORDER BY object_id) from sys.objects
)
select product,[order],1 as ord_qnty
from #temp t inner join Numbers num
on t.ord_qnty >= num.n
(In my nearly empty scratch database, the ROW_NUMBER() generates 77 rows. If that's not going to be enough, you can introduce cross-joins or use other tricks to generate more numbers, or you can create and populate a permanent numbers table)
Try this one -
Query:
DECLARE #temp TABLE
(
product INT
, [order] INT
, ord_qnty INT
)
INSERT #temp(product, [order], ord_qnty)
SELECT 10, 3, 4
SELECT
t.product
, t.[order]
, ord_qnty = 1
FROM #temp t
JOIN [master].dbo.spt_values sv ON t.ord_qnty > sv.number
WHERE sv.[type] = 'p'
SELECT
t.product
, t.[order]
, ord_qnty = 1
FROM #temp t
JOIN (
SELECT number = ROW_NUMBER() OVER (ORDER BY (SELECT 1))
FROM sys.system_parameters p
) sv ON t.ord_qnty >= sv.number
Output:
product order ord_qnty
----------- ----------- -----------
10 3 1
10 3 1
10 3 1
10 3 1
Query Cost:
For any "millions value":
SET NOCOUNT ON;
DECLARE #numbers TABLE (number INT)
DECLARE #temp TABLE
(
product INT
, [order] INT
, ord_qnty INT
)
INSERT #temp(product, [order], ord_qnty)
SELECT 10, 3, 4
DECLARE
#i BIGINT = 1
, #max BIGINT = (
SELECT MAX(ord_qnty)
FROM #temp
)
WHILE (#i <= #max) BEGIN
INSERT INTO #numbers (number)
VALUES (#i), (#i+1), (#i+2), (#i+3), (#i+4), (#i+5), (#i+6), (#i+7), (#i+8), (#i+9)
SELECT #i += 10
END
SELECT
t.product
, t.[order]
, ord_qnty = 1
FROM #temp t
CROSS JOIN (
SELECT *
FROM #numbers
WHERE number < #max + 1
) t2

Finding customers with identical orders

I need to find customers who have made identical orders. (Using T-SQL)
Order
OrderID Customerer
1 2
2 5
3 6
4 2
5 4
6 6
7 8
OrderLine
OrderLineID OrderID OrderDate OrderType Quantity Reference
1 1 01/01/2011 1 1 Coca Cola
2 1 01/01/2011 1 3 Tea
3 2 02/02/2011 2 1 Coffee
4 2 02/02/2011 2 2 Solo
5 2 03/02/2011 1 1 Soda
6 3 03/02/2011 1 3 Tea
7 3 03/02/2011 1 1 Coca Cola
8 4 05/06/2011 1 1 Beer
9 5 06/06/2011 2 1 Tea
10 5 06/06/2011 2 1 Coca Cola
11 6 07/07/2011 1 1 Coffee
12 6 07/07/2011 1 2 Solo
13 6 07/07/2011 1 1 Soda
14 6 07/07/2011 1 1 Beer
15 7 08/08/2011 1 1 Beer
Here orders with OrderID 1 and 3 are considered to be identical because the number for orderlines, "Quantity" and "Reference" are identical on both orders. Meaning that customer 2 and 6 have placed identical orders.
Order 5 are not identical to order 1 and 3 because Quantity differ.
Order 2 are not identical to order 6 because orderlines differ.
Order 4 and 7 are also identical.
I am searching for a ressult like this:
IdenticalOrders
OrderID CustomeerID
1 2
3 6
4 2
7 8
It seems like an easy task, but I just can't understand where to start.
(I am still new to t-sql :-) )
Here's one way.
SELECT O1.OrderID ,
O1.Customer ,
O2.OrderID ,
O2.Customer
FROM [Order] O1
JOIN [Order] O2 ON O1.OrderID < O2.OrderID
AND O1.Customer <> O2.Customer
WHERE NOT EXISTS ( SELECT Quantity ,
Reference
FROM OrderLine
WHERE O1.OrderID = OrderLine.OrderID
EXCEPT
SELECT Quantity ,
Reference
FROM OrderLine
WHERE O2.OrderID = OrderLine.OrderID )
AND NOT EXISTS ( SELECT Quantity ,
Reference
FROM OrderLine
WHERE O2.OrderID = OrderLine.OrderID
EXCEPT
SELECT Quantity ,
Reference
FROM OrderLine
WHERE O1.OrderID = OrderLine.OrderID )
You can also use XML PATH to simulate GROUP_CONCAT then JOIN the two result sets
DECLARE #T TABLE
(
OrderId INT PRIMARY KEY,
Customer INT ,
complete_order VARCHAR(MAX)
)
INSERT INTO #T
SELECT *
FROM [Order] O
CROSS APPLY ( SELECT CAST(Quantity AS VARCHAR(30))
+ '~' + Reference + '~~'
FROM OrderLine OL
WHERE OL.OrderID = O.OrderID
ORDER BY Reference ,
Quantity
FOR
XML PATH('')
) T ( complete_order )
SELECT T1.OrderId,
T1.Customer
FROM #T T1
WHERE EXISTS ( SELECT *
FROM #T T2
WHERE T1.Customer <> T2.Customer
AND T1.OrderId <> T2.OrderId
AND T1.complete_order = T2.complete_order )
This is an extension of Martin's second suggestion. This will show all matching combinations without any repetitions.
;With FmtOL(customer, orderid, complete_order) as
(
SELECT customer, orderid, complete_order
FROM Order O
cross apply ( SELECT CAST(Quantity AS VARCHAR(30))
+ '~' + Reference + '~~'
FROM OrderLine OL
WHERE OL.OrderID = O.OrderID
ORDER BY Reference ,
Quantity
FOR
XML PATH('')
) T ( complete_order )
)
SELECT T1.OrderId,
T1.Customer,
STUFF(C1.a, 1, 2, '') as [SameAs]
FROM FmtOL T1
Cross apply ( SELECT '; ' + 'Customer ' + Cast(T2.Customer as varchar(30))
+ '''s order ' + Cast(T2.OrderID as varchar(30))
FROM FmtOL T2
WHERE T1.Customer < T2.Customer
AND T1.OrderId < T2.OrderId
AND T1.complete_order = T2.complete_order
order by ';' + Cast(T2.Customer as varchar(30))
+ '''s order ' + Cast(T2.OrderID as varchar(30))
, t2.orderid
for xml path('')
) C1 (a)
where C1.a is not null
Results should look like this:
OrderId Customer SameAs
1 2 Customer 6's order 3
4 2 Customer 8's order 7
Here's the most simple approach.
-- sample table
create table x
(
LineId int identity(1, 1)
,InvoiceFk int
,ProductFk int
,Quantity int
)
-- sample data
insert into x
(InvoiceFk, ProductFk, Quantity) values
(11, 1, 1)
,(11, 2, 1)
,(11, 3, 1)
,(12, 1, 2)
,(12, 2, 2)
,(12, 3, 2)
,(13, 1, 3)
,(13, 2, 3)
,(13, 3, 3)
-- your order, probably from a parameter
declare #order table
(
InvoiceFk int
,ProductFk int
,Quantity int
)
insert into #order
(InvoiceFk, ProductFk, Quantity) values
(14, 1, 1) -- duplicate invoice 11
,(14, 2, 1)
,(14, 3, 1)
-- your order unique checksum
declare #orderCheck int
select #orderCheck = checksum_agg(checksum(ProductFk, Quantity))
from #order
-- test your order in existing data
declare #match int
select #match =
(
select TOP 1 InvoiceFk from
(
select
InvoiceFk
,checksum_agg(Col1) as Col2
from
(
select
InvoiceFk
,checksum(productfk, quantity) as Col1
from x
) as T1
group by
InvoiceFk
) as T2
where
T2.Col2 = #orderCheck
)
-- evaluate if your order is unique or not
if (#match is not null)
begin
print 'Identical to invoice: ' + Str(#match);
end
else
begin
print 'Order is unique';
end
-- clean up sample table
drop table x
Best of luck!

Resources