Show ordered Articles per User - sql-server

I have the following:
customerID | OrderID | OrderPosition | Articlenumber|
-----------+---------+---------------+--------------+
101 | 1 | 1 | 123 |
101 | 1 | 2 | 799 |
102 | 2 | 1 | 111 |
103 | 3 | 1 | 456 |
101 | 4 | 1 | 789 |
103 | 5 | 1 | 444 |
103 | 5 | 2 | 999 |
101 | 6 | 1 | 555 |
101 | 6 | 2 | 777 |
101 | 6 | 3 | 222 |
and I want the following (sum up max 4 articles (ordered by orderID (higher first) and OrderPosition (lower first)) per customerID):
customerID |articelnumber 1|articelnumber 2|articelnumber 3|articelnumber 4|
-------+-------------------+---------------+---------------+---------------+
101 |555 |777 |222 | 789 |
102 |111 |NULL |NULL |NULL |
103 |444 |999 |456 |NULL |
Tried it like this this, but this is not working correct:
select *
from
(
select customerid, OrderID , OrderPosition, Articlenumber FROM table
) src
pivot
(
avg (Articlenumber)
for OrderPosition in ([articelnumber 1], [articelnumber 2], [articelnumber 3], [articelnumber 4])
) piv

It took me a while to get to the same results as your expected output, but I managed to get it right eventually:
if exists (select 1 from sysobjects where name = 'TempTable')
drop table TempTable;
if exists (select 1 from sysobjects where name = 'TempTable2')
drop table TempTable2;
declare #cols nvarchar(max)
, #cols2 nvarchar(max)
, #sql nvarchar(max)
, #loop int;
create table TempTable (id int primary key identity, CustomerID int, OrderID int, OrderPosition int, ArticleNumber int)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,1,1,123)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,1,2,799)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (102,2,1,111)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (103,3,1,456)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,4,1,789)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (103,5,1,444)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (103,5,2,999)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,6,1,555)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,6,2,777)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,6,3,222);
create table TempTable2 (CustomerID int, OrderID int, OrderPosition int, ArticleNumber int, ArticleDesc varchar(100))
select #loop = min(id) from TempTable
while #loop is not null
begin
set #sql = ' insert into TempTable2 (CustomerID, OrderID, OrderPosition, ArticleNumber, ArticleDesc)
select top 4 CustomerID, OrderID, OrderPosition, ArticleNumber, ''ArticleNumber ''+cast(rank() over (order by orderID desc, OrderPosition)as varchar)
from TempTable where CustomerID = '+cast((select CustomerID from TempTable where id = #loop) as varchar)+
'order by orderID desc, OrderPosition'
exec (#sql)
select #loop = min(id) from TempTable where id > #loop
end
select
CustomerID
, sum(isnull([ArticleNumber 1],0)) [ArticleNumber 1]
, sum(isnull([ArticleNumber 2],0)) [ArticleNumber 2]
, sum(isnull([ArticleNumber 3],0)) [ArticleNumber 3]
, sum(isnull([ArticleNumber 4],0)) [ArticleNumber 4]
from
(
select
CustomerID, OrderID, OrderPosition, ArticleDesc, ArticleNumber
from TempTable2
group by CustomerID, OrderID, OrderPosition, ArticleDesc, ArticleNumber
) d
pivot
(sum(ArticleNumber) for ArticleDesc in ([ArticleNumber 1],[ArticleNumber 2],[ArticleNumber 3],[ArticleNumber 4])
) p
group by CustomerID
My answer might not be the best as the genius guys answered above, but I still get the same results...

If you're after just four columns and a quick output the same as listed above, you can always just use ROW_NUMBER, a CTE, and a few joins:
;with TopFour
as
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY [customerID] ORDER BY orderID DESC, OrderPosition ASC) as [TheOrder]
FROM [table]
)
SELECT
a.[customerID],
a.[Articlenumber] as [articlenumber 1],
b.[Articlenumber] as [articlenumber 2],
c.[Articlenumber] as [articlenumber 3],
d.[Articlenumber] as [articlenumber 4]
FROM
TopFour a
LEFT JOIN
TopFour b
ON
a.customerID = b.customerID
AND
b.TheOrder = 2
LEFT JOIN
TopFour c
ON
a.customerID = c.customerID
AND
c.TheOrder = 3
LEFT JOIN
TopFour d
ON
a.customerID = d.customerID
AND
d.TheOrder = 4
WHERE
a.TheOrder = 1

Modified Sample Data to meet Your Requirement
IF OBJECT_ID('tempdb..#TEMP ')IS NOT NULL
DROP TABLE #TEMP
;WITH CTE(customerID , OrderID , OrderPosition , Articlenumber)
AS
(
SELECT 101, 1 , 1 , 123 UNION ALL
SELECT 101, 1 , 2 , 799 UNION ALL
SELECT 102, 2 , 1 , 111 UNION ALL
SELECT 103, 3 , 1 , 456 UNION ALL
SELECT 101, 4 , 1 , 789 UNION ALL
SELECT 103, 5 , 1 , 444 UNION ALL
SELECT 103, 5 , 2 , 999 UNION ALL
SELECT 101, 6 , 1 , 555 UNION ALL
SELECT 101, 6 , 2 , 777 UNION ALL
SELECT 101, 6 , 3 , 222
)
SELECT * , SUM(ArticleNumber)OVER(PARTITION BY customerID ORDER BY customerID ) AS SumOfArticlePerCustomer
INTO #TEMP
FROM
(
SELECT * ,
ROW_NUMBER()OVER(PARTITION BY customerID ORDER BY OrderID DESC ) RNk,
'ArticleNumber_'+CAST(ROW_NUMBER()OVER(PARTITION BY customerID ORDER BY OrderID DESC ) AS VARCHAR(10)) AS ArticleNumberData
FROM CTE
)DT
WHERE RNk <= 4
SELECT * FROM #TEMP
Dynamic Sql ,which is used to get generate the column dynamically and meet the expected result
DECLARE #Sql nvarchar(max),
#DynamicColumn nvarchar(max),
#MaxDynamicColumn nvarchar(max)
SELECT #DynamicColumn = STUFF((SELECT DISTINCT', '+QUOTENAME(ArticleNumberData )
FROM #TEMP FOR XML PATH ('')),1,1,'')
SELECT #MaxDynamicColumn = STUFF((SELECT DISTINCT', '+'MAX('+QUOTENAME(ArticleNumberData )+') AS '+QUOTENAME(ArticleNumberData )+CHAR(13)+CHAR(10)
FROM #TEMP FOR XML PATH (''),TYPE).value('text()[1]','nvarchar(max)'),1,1,N'')
SET #Sql='SELECT CustomerID,'+ #MaxDynamicColumn+',SumOfArticlePerCustomer
FROM
(
SELECT *
FROM #TEMP
)AS src
PIVOT
(
MAX(Articlenumber) FOR [ArticleNumberData] IN ('+#DynamicColumn+')
) AS Pvt
GROUP BY customerID,SumOfArticlePerCustomer
ORDER BY CustomerID'
EXEC (#Sql)
PRINT #Sql

Related

Pivoting table in SQL

i have a problem with approach how to pivot this table:
How can i convert this:
Would you be kind enough give me hints (not whole code) how to do this? i really dont know where should i start (i dont know whether it is typical pivoting unpivoting)
+------+------+--------+----------+-----------+-----+
| ColI | Col2 | Month | Turnover | Provision | Fee |
+------+------+--------+----------+-----------+-----+
| 123 | Asdf | 201810 | 10000 | 100 | 0,1 |
| 123 | Asdf | 201811 | 20000 | 200 | 0,2 |
| 123 | Asdf | 201812 | 30000 | 300 | 0,3 |
+------+------+--------+----------+-----------+-----+
into this:
+------+------+---------------+-----------------+------------+---------------+-----------------+------------+---------------+-----------------+-----------+
| ColI | Col2 | Turnover20810 | Provision201810 | Fee201810 | Turnover20811 | Provision201811 | Fee201811 | Turnover20812 | Provision201812 | Fee201812 |
+------+------+---------------+-----------------+------------+---------------+-----------------+------------+---------------+-----------------+-----------+
| 123 | Asdf | 10000 | 100 | 0,1 | 20000 | 200 | 0,2 | 30000 | 300 | 0,3 |
+------+------+---------------+-----------------+------------+---------------+-----------------+------------+---------------+-----------------+-----------+
Thank you!
Assuming that each ColI, Col2 group would only have a maximum of three records, then we can try pivoting using the help of ROW_NUMBER:
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ColI, Col2 ORDER BY Month) rn
FROM yourTable
)
SELECT
ColI,
Col2,
MAX(CASE WHEN rn = 1 THEN Turnover END) AS Turnover1,
MAX(CASE WHEN rn = 1 THEN Provision END) AS Provision1,
MAX(CASE WHEN rn = 1 THEN Fee END) AS Fee1,
MAX(CASE WHEN rn = 2 THEN Turnover END) AS Turnover2,
MAX(CASE WHEN rn = 2 THEN Provision END) AS Provision2,
MAX(CASE WHEN rn = 2 THEN Fee END) AS Fee2,
MAX(CASE WHEN rn = 3 THEN Turnover END) AS Turnover3,
MAX(CASE WHEN rn = 3 THEN Provision END) AS Provision3,
MAX(CASE WHEN rn = 3 THEN Fee END) AS Fee3
FROM cte
GROUP BY
ColI,
Col2;
Note that I did not hardwire more specific column names, to keep the query as general as possible. For example, perhaps there might be another ColI, Col2 group which would have a different three months.
By using Dynamic Sql
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
;WITH CTE (ColI , Col2 , Month , Turnover , Provision , Fee )
AS
(
SELECT 123 , 'Asdf' , 201810 , 10000 ,100 ,'0,1' UNION ALL
SELECT 123 , 'Asdf' , 201811 , 20000 ,200 , '0,2' UNION ALL
SELECT 123 , 'Asdf' , 201812 , 30000 ,300 , '0,3'
)
SELECT ColI , Col2,Turnover , Provision , Fee,MixedCol,Reqcol , ROW_NUMBER()OVER(ORDER BY (SELECT NULL)) AS Seq
INTO #Temp
FROM CTE
CROSS APPLY (VALUES (CONCAT('Turnover','_',[Month]),CAST(Turnover AS VARCHAR(20))),
(CONCAT('Provision','_',[Month]),CAST(Provision AS VARCHAR(20))),
(CONCAT('Fee','_',[Month]),CAST(Fee AS VARCHAR(20)))
)DT (MixedCol,Reqcol)
DECLARE #Sql nvarchar(max),
#DynamicColumn nvarchar(max),
#MaxDynamicColumn nvarchar(max)
SELECT #DynamicColumn = STUFF((SELECT ', '+QUOTENAME(CAST(MixedCol AS VARCHAR(100)))
FROM #TEMP ORDER BY Seq FOR XML PATH ('')),1,1,'')
SELECT #MaxDynamicColumn = STUFF((SELECT ', '+'MAX('+QUOTENAME(CAST(MixedCol AS VARCHAR(100)))+') AS '+QUOTENAME(CAST(MixedCol AS VARCHAR(100)))
FROM #TEMP ORDER BY Seq FOR XML PATH ('')),1,1,'')
SET #Sql=' SELECT ColI , Col2,'+ #MaxDynamicColumn+'
FROM
(
SELECT * FROM #TEMP
)AS src
PIVOT
(
MAX(Reqcol) FOR [MixedCol] IN ('+#DynamicColumn+')
) AS Pvt
GROUP BY ColI , Col2 '
EXEC (#Sql)
PRINT #Sql
Q: "...give me hints (not whole code) how to do this"
A: This example with dynamic transpose of table. You can try this. Unpivot your original table and transpose.
CREATE table #tbl (
color varchar(10), Paul int, John int, Tim int, Eric int);
insert #tbl select
'Red' ,1 ,5 ,1 ,3 union all select
'Green' ,8 ,4 ,3 ,5 union all select
'Blue' ,2 ,2 ,9 ,1;
select * FROM #tbl
--1) Transpose. Example without dynamic code. You create list of fields in query
select *
from #tbl
unpivot (value for name in ([Paul],[John],[Tim],[Eric])) up
pivot (max(value) for color in ([Blue],[Green],[Red])) p
--2) Transpose. Example with dynamic code, without names of fields.
DECLARE #cols NVARCHAR(MAX), #query NVARCHAR(MAX), #rows NVARCHAR(MAX)='';
-- XML with all values
SET #cols = STUFF(
(
SELECT DISTINCT
','+QUOTENAME(T.Color) -- Name of first column
FROM #tbl T FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 1, '');
SELECT #rows=#rows+','+QUOTENAME(Name)
FROM
(SELECT Name,ROW_NUMBER() OVER(ORDER BY column_id) AS 'RowNum'
FROM tempdb.sys.Columns
WHERE Object_ID = OBJECT_ID('tempdb..#tbl')
) AS A WHERE A.RowNum>1
SET #rows=STUFF(#rows,1,1,'')
SET #query='SELECT *
from #tbl
unpivot (value for name in ('+#rows+')) up
pivot (max(value) for color in ('+#Cols+')) p'
EXEC (#query)

Make query like treeview

Brothers can you help me? Thanks
Table A
Id Name IdParent
1 Operation Null
2 Developer 1
3 Android 2
4 IOS 2
Expectes result:
ID Name
1 +Operation
2 +------ Developer
3 +------------Android
4 +------------ IOS
By adding a sequence during the recursive build, you can easily create the proper presentation sequence and nesting
Declare #YourTable table (id int,IdParent int,Name varchar(50))
Insert into #YourTable values
( 1, NULL,'Operation')
,( 2, 1 ,'Developer')
,( 3, 2 ,'Android')
,( 4, 2 ,'IOS')
,( 5, 1 ,'Poet')
,( 6, 5 ,'Limerick')
,( 7, 5 ,'Haiku')
Declare #Top int = null --<< Sets top of Hier Try 2
Declare #Nest varchar(25) = '|-----' --<< Optional: Added for readability
;with cteP as (
Select Seq = cast(10000+Row_Number() over (Order by Name) as varchar(500))
,ID
,IdParent
,Lvl=1
,Name
From #YourTable
Where IsNull(#Top,-1) = case when #Top is null then isnull(IdParent ,-1) else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.Name)) as varchar(500))
,r.ID
,r.IdParent
,p.Lvl+1
,r.Name
From #YourTable r
Join cteP p on r.IdParent = p.ID)
Select A.ID
,A.IdParent
,A.Lvl
,Name = Replicate(#Nest,A.Lvl-1) + A.Name
From ctep A
Order By A.Seq
Returns
ID IdParent Lvl Name
1 NULL 1 Operation
2 1 2 |-----Developer
3 2 3 |-----|-----Android
4 2 3 |-----|-----IOS
5 1 2 |-----Poet
7 5 3 |-----|-----Haiku
6 5 3 |-----|-----Limerick
Here's another version:
WITH RawData AS (
SELECT 1 AS Id, 'Operation' AS Name, CONVERT(INT, NULL) AS IdParent
UNION ALL
SELECT 2 AS Id, 'Developer' AS Name, 1 AS IdParent
UNION ALL
SELECT 3 AS Id, 'Android' AS Name, 2 AS IdParent
UNION ALL
SELECT 4 AS Id, 'IOS' AS Name, 2 AS IdParent),
Depth AS (
SELECT
Id,
1 AS depth,
IdParent
FROM
RawData
UNION ALL
SELECT
d.Id,
d.depth + 1,
r.IdParent
FROM
Depth d
INNER JOIN RawData r ON r.Id = d.IdParent),
MaxDepth AS (
SELECT
Id,
MAX(depth) AS depth
FROM
Depth
GROUP BY
Id)
SELECT
r.Id,
'+' + REPLICATE('----', m.depth - 1) + r.Name AS Name
FROM
RawData r
INNER JOIN MaxDepth m ON m.Id = r.Id;
Results:
Id Name
1 +Operation
2 +----Developer
3 +--------Android
4 +--------IOS
DECLARE #mockup TABLE(Id INT, Name VARCHAR(100), IdParent INT);
INSERT INTO #mockup VALUES
(1,'Operation',Null)
,(2,'Developer',1)
,(3,'Android',2)
,(4,'IOS',2);
--The query uses a recursive CTE and finally REPLICATE with the recursive level to add the number of hyphens...
WITH recCTE AS
(
SELECT Id, Name, 1 AS Lvl, CAST(REPLACE(STR(ROW_NUMBER() OVER (ORDER BY Id),5),' ','0') AS VARCHAR(MAX)) AS Seq
FROM #mockup
WHERE IdParent IS NULL
UNION ALL
SELECT m.Id,m.Name,r.Lvl +1,r.Seq + '.' + REPLACE(STR(ROW_NUMBER() OVER (ORDER BY m.Id),5),' ','0')
FROM #mockup AS m
INNER JOIN recCTE AS r ON m.IdParent=r.Id
)
SELECT *
,'+' + REPLICATE('-',Lvl*4) + Name
FROM recCTE
ORDER BY Seq
the result
+----+-----------+-----+----------------------+
| Id | Name | Lvl | (Kein Spaltenname) |
+----+-----------+-----+----------------------+
| 1 | Operation | 1 | +----Operation |
+----+-----------+-----+----------------------+
| 2 | Developer | 2 | +--------Developer |
+----+-----------+-----+----------------------+
| 3 | Android | 3 | +------------Android |
+----+-----------+-----+----------------------+
| 4 | IOS | 3 | +------------IOS |
+----+-----------+-----+----------------------+

Recursive sum in tree structure

I have a tree struture in a single table. The table is a tree of categories that can be nested endlessly. Each category has a ProductCount column that tells how many products are directly in the category (not summing child categories).
Id | ParentId | Name | ProductCount
------------------------------------
1 | -1 | Cars | 0
2 | -1 | Bikes | 1
3 | 1 | Ford | 10
4 | 3 | Mustang | 7
5 | 3 | Focus | 4
I would like to make a sql query that for each row/category gives me the number of products including the ones in the child categories.
The output for the table above should be
Id | ParentId | Name | ProductCount | ProductCountIncludingChildren
--------------------------------------------------------------------------
1 | -1 | Cars | 0 | 21
2 | -1 | Bikes | 1 | 1
3 | 1 | Ford | 10 | 21
4 | 3 | Mustang | 7 | 7
5 | 3 | Focus | 4 | 4
I know I probably should use CTE, but cant quite get it working the way it should.
Any help is appreciated!
You can use a recursive CTE where you in the anchor part get all rows and in the recursive part join to get the child rows. Remember the original Id aliased RootID from the anchor part and do sum aggregate in the main query grouped by RootID.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table T
(
Id int primary key,
ParentId int,
Name varchar(10),
ProductCount int
);
insert into T values
(1, -1, 'Cars', 0),
(2, -1, 'Bikes', 1),
(3, 1, 'Ford', 10),
(4, 3, 'Mustang', 7),
(5, 3, 'Focus', 4);
create index IX_T_ParentID on T(ParentID) include(ProductCount, Id);
Query 1:
with C as
(
select T.Id,
T.ProductCount,
T.Id as RootID
from T
union all
select T.Id,
T.ProductCount,
C.RootID
from T
inner join C
on T.ParentId = C.Id
)
select T.Id,
T.ParentId,
T.Name,
T.ProductCount,
S.ProductCountIncludingChildren
from T
inner join (
select RootID,
sum(ProductCount) as ProductCountIncludingChildren
from C
group by RootID
) as S
on T.Id = S.RootID
order by T.Id
option (maxrecursion 0)
Results:
| ID | PARENTID | NAME | PRODUCTCOUNT | PRODUCTCOUNTINCLUDINGCHILDREN |
|----|----------|---------|--------------|-------------------------------|
| 1 | -1 | Cars | 0 | 21 |
| 2 | -1 | Bikes | 1 | 1 |
| 3 | 1 | Ford | 10 | 21 |
| 4 | 3 | Mustang | 7 | 7 |
| 5 | 3 | Focus | 4 | 4 |
This is the same concept as Tom's answer, but less code (and way faster).
with cte as
(
select v.Id, v.ParentId, v.Name, v.ProductCount,
cast('/' + cast(v.Id as varchar) + '/' as varchar) Node
from Vehicle v
where ParentId = -1
union all
select v.Id, v.ParentId, v.Name, v.ProductCount,
cast(c.Node + CAST(v.Id as varchar) + '/' as varchar)
from Vehicle v
join cte c on v.ParentId = c.Id
)
select c1.Id, c1.ParentId, c1.Name, c1.ProductCount,
c1.ProductCount + SUM(isnull(c2.ProductCount, 0)) ProductCountIncludingChildren
from cte c1
left outer join cte c2 on c1.Node <> c2.Node and left(c2.Node, LEN(c1.Node)) = c1.Node
group by c1.Id, c1.ParentId, c1.Name, c1.ProductCount
order by c1.Id
SQL Fiddle (I added some extra data rows for testing)
Actually this could be a good use of HIERARCHYID in SQL Server..
CREATE TABLE [dbo].[CategoryTree]
(
[Id] INT,
[ParentId] INT,
[Name] VARCHAR(100),
[ProductCount] INT
)
GO
INSERT [dbo].[CategoryTree]
VALUES
(1, -1, 'Cars', 0),
(2, -1, 'Bikes', 1),
(3, 1, 'Ford', 10),
(4, 3, 'Mustang', 7),
(5, 3, 'Focus', 4)
--,(6, 1, 'BMW', 100)
GO
Query
WITH [cteRN] AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY [ParentId] ORDER BY [ParentId]) AS [ROW_NUMBER]
FROM [dbo].[CategoryTree]
),
[cteHierarchy] AS (
SELECT CAST(
CAST(hierarchyid::GetRoot() AS VARCHAR(100))
+ CAST([ROW_NUMBER] AS VARCHAR(100))
+ '/' AS HIERARCHYID
) AS [Node],
*
FROM [cteRN]
WHERE [ParentId] = -1
UNION ALL
SELECT CAST(
hierarchy.Node.ToString()
+ CAST(RN.[ROW_NUMBER] AS VARCHAR(100)
) + '/' AS HIERARCHYID),
rn.*
FROM [cteRN] rn
INNER JOIN [cteHierarchy] hierarchy
ON rn.[ParentId] = hierarchy.[Id]
)
SELECT x.[Node].ToString() AS [Node],
x.[Id], x.[ParentId], x.[Name], x.[ProductCount],
x.[ProductCount] + SUM(ISNULL(child.[ProductCount],0))
AS [ProductCountIncludingChildren]
FROM [cteHierarchy] x
LEFT JOIN [cteHierarchy] child
ON child.[Node].IsDescendantOf(x.[Node]) = 1
AND child.[Node] <> x.[Node]
GROUP BY x.[Node], x.[Id], x.[ParentId], x.[Name], x.[ProductCount]
ORDER BY x.[Id]
Result
This wont be optimal but it works, however it involves 2 CTEs. 1 main CTE and a CTE in a table valued function to sum up the values for each sub tree.
The first CTE
;WITH cte
AS
(
SELECT
anchor.Id,
anchor.ParentId,
anchor.Name,
anchor.ProductCount,
s.Total AS ProductCountIncludingChildren
FROM
testTable anchor
CROSS APPLY SumChild(anchor.id) s
WHERE anchor.parentid = -1
UNION ALL
SELECT
child.Id,
child.ParentId,
child.Name,
child.ProductCount,
s.Total AS ProductCountIncludingChildren
FROM
cte
INNER JOIN testTable child on child.parentid = cte.id
CROSS APPLY SumChild(child.id) s
)
SELECT * from cte
AND the function
CREATE FUNCTION SumChild
(
#id int
)
RETURNS TABLE
AS
RETURN
(
WITH cte
AS
(
SELECT
anchor.Id,
anchor.ParentId,
anchor.ProductCount
FROM
testTable anchor
WHERE anchor.id = #id
UNION ALL
SELECT
child.Id,
child.ParentId,
child.ProductCount
FROM
cte
INNER JOIN testTable child on child.parentid = cte.id
)
SELECT SUM(ProductCount) AS Total from CTE
)
GO
Which results in:
from the source table
Apologies about formatting.
I couldn't come up with a good T-SQL, set based answer, but I did come up with an answer:
The temp table mimics your table structure. The table variable is a work table.
--Initial table
CREATE TABLE #products (Id INT, ParentId INT, NAME VARCHAR(255), ProductCount INT)
INSERT INTO #products
( ID,ParentId, NAME, ProductCount )
VALUES ( 1,-1,'Cars',0),(2,-1,'Bikes',1),(3,1,'Ford',10),(4,3,'Mustang',7),(5,3,'Focus',4)
--Work table
DECLARE #products TABLE (ID INT, ParentId INT, NAME VARCHAR(255), ProductCount INT, ProductCountIncludingChildren INT)
INSERT INTO #products
( ID ,
ParentId ,
NAME ,
ProductCount ,
ProductCountIncludingChildren
)
SELECT Id ,
ParentId ,
NAME ,
ProductCount,
0
FROM #products
DECLARE #i INT
SELECT #i = MAX(id) FROM #products
--Stupid loop - loops suck
WHILE #i > 0
BEGIN
WITH cte AS (SELECT ParentId, SUM(ProductCountIncludingChildren) AS ProductCountIncludingChildren FROM #products GROUP BY ParentId)
UPDATE p1
SET p1.ProductCountIncludingChildren = p1.ProductCount + isnull(p2.ProductCountIncludingChildren,0)
FROM #products p1
LEFT OUTER JOIN cte p2 ON p1.ID = p2.ParentId
WHERE p1.ID = #i
SELECT #i = #i - 1
END
SELECT *
FROM #products
DROP TABLE #products
I'd be very interested to see a better, set based approach. The problem I ran into is that when you use recursive cte's, you start with the parent and work toward the children - this doesn't really work for getting a sum at the parent levels. You'd have to do some kind of backward recursive cte.

Ms sql, how to add 2 new columns using autonumber as their counter? in query

here is the link of the picture:
help i need to create something like table 3..
i already have a query that has them all except for the count2 column, i don't know how to create that in query..
here's my code in query:
SELECT a.rn,'',a.id, b.iddesc
INTO #x
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [desc]) AS rn, *
FROM aa
) a, bb AS b
WHERE b.idcon = a.id
SELECT *
FROM #x
sorry i don't know how to explain it well,
Try this one -
Query:
DECLARE #table_a TABLE (id INT, [desc] NVARCHAR(50))
INSERT INTO #table_a (id, [desc])
VALUES
(221, 'aaa'),(222, 'sss'),
(223, 'ddd'),(225, 'fff')
DECLARE #table_b TABLE (idcon INT, iddesc NVARCHAR(50))
INSERT INTO #table_b (idcon, iddesc)
VALUES
(221, 'zxc'),(221, 'sad'),
(221, 'fdfg'),
(222, 'asd'),(222, 'vcx'),
(223, 'zxc'),(223, 'asd'),
(224, 'cxv'),(224, 'asd'),
(225, 'zcx'),(225, 'asd'),
(225, 'qwe'),(225, 'wer')
SELECT
idcon
, [desc] = iddesc
, count1
, count2 = ROW_NUMBER() OVER (PARTITION BY id ORDER BY [desc]) - 1
FROM (
SELECT *, count1 = ROW_NUMBER() OVER (ORDER BY id)
FROM #table_a
) a
JOIN #table_b ON id = idcon
Results:
idcon desc count1 count2
------- ------ ------- -------
221 zxc 1 0
221 sad 1 1
221 fdfg 1 2
222 asd 2 0
222 vcx 2 1
223 zxc 3 0
223 asd 3 1
225 zcx 4 0
225 asd 4 1
225 qwe 4 2
225 wer 4 3
Try this
SELECT
DENSE_RANK() OVER (ORDER BY idcon) AS Count1
, (ROW_NUMBER() OVER (PARTITION BY idcon ORDER BY idcon)) - 1 AS Count2
, idcon
, iddesc
FROM Table_b b
INNER JOIN Table_a a ON a.ID = b.idcon
Here is SQLFiddle demo

Fetching Records from multiple tables month wise

I am having scenario like this : I am having many tables and each table has date fields.
Table: FA
Id | Created_Date |
------------------------
1 | 1/12/2012 |
2 | 2/15/2012 |
3 | 2/25/2012 |
Table: TPA
Id | Created_Date |
------------------------
1 | 3/10/2012 |
2 | 4/25/2012 |
3 | 5/20/2012 |
4 | 5/21/2012 |
Table: Gift
Id | Created_Date |
------------------------
1 | 6/10/2012 |
2 | 7/25/2012 |
3 | 8/10/2012 |
3 | 7/11/2012 |
I want output like I want total count of records from each table and display it respective to month wise by using Created_Date field dates.
Expected Output like this:
Give this solution a try,
SELECT MonthName,
COALESCE(FA, 0) FA,
COALESCE(TPA, 0) TPA,
COALESCE(GIFT, 0) GIFT
FROM
(
SELECT monthList.ordby,
monthList.MonthName,
org.TableName,
org.TotalCount
FROM
(
SELECT 1 ordby, 'January' MonthName UNION SELECT 2, 'February' UNION
SELECT 3, 'March' UNION SELECT 4, 'April' UNION
SELECT 5,'May' UNION SELECT 6,'June' UNION
SELECT 7,'July' UNION SELECT 8,'August' UNION
SELECT 9,'September' UNION SELECT 10,'October' UNION
SELECT 11,'November' UNION SELECT 12,'December'
) monthList
LEFT JOIN
(
SELECT 'FA' TableName,
DATENAME(mm,Created_Date) MonthName,
COUNT(*) TotalCount
FROM FA
GROUP BY DATENAME(mm,Created_Date)
UNION
SELECT 'TPA' TableName,
DATENAME(mm,Created_Date) MonthName,
COUNT(*) TotalCount
FROM TPA
GROUP BY DATENAME(mm,Created_Date)
UNION
SELECT 'Gift' TableName,
DATENAME(mm,Created_Date) MonthName,
COUNT(*) TotalCount
FROM Gift
GROUP BY DATENAME(mm,Created_Date)
) org ON monthList.MonthName = org.MonthName
) data
PIVOT
(
MAX(TotalCount)
FOR TableName IN ([FA], [TPA],[GIFT])
) head
ORDER BY ordby
http://www.sqlfiddle.com/#!3/dc613/14
I was trying to get the Find the solution since last 4 Hours
I think my answer is Low in Performance as Compare to above Answer,
create table #month
(
id [int] IDENTITY(1,1) NOT NULL,
[month] varchar(3)
)
DBCC CHECKIDENT(#month, RESEED, 1)
insert into #month
values
('Jan'),
('Feb'),
('Mar'),
('Apr'),
('May'),
('Jun'),
('Jul'),
('Aug'),
('Sep'),
('Oct'),
('Nov'),
('Dec')
declare #id int
set #id=1
declare #month varchar(3)
declare #sql nvarchar(max)
set #sql=''
declare #order varchar(3)
while (#id<13)
BEGIN
set #month=(select [month] from #month where id=#id)
set #order=CONVERT(varchar(3),#id)
set #sql=#sql+'insert into #display
(
[Month],
[COUNT(FA)],
[COUNT(TPA)],
[COUNT(Gift)],
[ORDER]
)
select '''+ #month +''' AS [Month],
(select
COUNT(CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100))
from FA
where CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100)='''+ #month +''') [COUNT(FA)],
(select
COUNT(CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100))
from TPA
where CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100)='''+ #month +''') [COUNT(TPA)],
(select
COUNT(CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100))
from Gift
where CONVERT(VARCHAR(3), DATENAME(MM,Created_Date), 100)='''+ #month +''') [COUNT(Gift)],
'''+ #order + ''' [Order]
'
set #id=#id+1 --Incrementing the month
END
exec sp_executesql #sql
print #sql
select [MONTH],
[COUNT(FA)],
[COUNT(TPA)],
[COUNT(Gift)]
from #display
order by convert(int,[ORDER])

Resources