Dynamic pivot and initialization with a constant (without sum) - sql-server

I have two Tables: TbOrder and TbProduct. These tables are correlated by a condition on a number progression through the '&' operator. If the condition is true I should assign the product to the relative order.
CREATE TABLE [dbo].[TbOrder](
[Id] [bigint] NOT NULL,
[Flag] [bigint] NOT NULL,
CONSTRAINT [PK_TbOrder] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[TbProduct](
[Id] [bigint] NOT NULL,
[Flag] [bigint] NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_TbProduct] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[TbOrder] ([Id], [Flag]) VALUES (1, 5124)
INSERT [dbo].[TbOrder] ([Id], [Flag]) VALUES (2, 10507925)
INSERT [dbo].[TbOrder] ([Id], [Flag]) VALUES (3, 10053569)
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (1, 4, N'Prod1')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (2, 1024, N'Prod2')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (3, 4096, N'Prod3')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (4, 2, N'Prod4')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (5, 1, N'Prod5')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (6, 8, N'Prod6')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (7, 512, N'Prod7')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (8, 32, N'Prod8')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (9, 16, N'Prod9')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (10, 128, N'Prod10')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (11, 64, N'Prod11')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (12, 1, N'Prod12')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (13, 8192, N'Prod13')
INSERT [dbo].[TbProduct] ([Id], [Flag], [Name]) VALUES (14, 16384, N'Prod14')
The query and the result are as follow:
select o.Id OrderId, o.Flag OrderFlag, p.Id ProductId,
p.Flag ProductFlag, p.Name ProductName from TbOrder o
inner join TbProduct p on (o.Flag & p.Flag)=p.Flag
I tried with Pivot but the result compared to the first query remained unchanged (removing the line --'x').
select * from
(select o.Id OrderId, o.Flag OrderFlag, p.Id ProductId, p.Flag ProductFlag, p.Name ProductName from TbOrder o
inner join TbProduct p on (o.Flag & p.Flag)=p.Flag) t
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols += QUOTENAME(Name) + ','
FROM TbProduct
ORDER BY FLAG;
SET #cols = LEFT(#cols, LEN(#cols) - 1);
print #cols;
SELECT #query = '
SELECT t.* FROM t
PIVOT
(
--'x'
FOR t.Name IN( ' + #cols + ' )
) AS pivot_table; ';
execute(#query)
What I would like obtain instead is a single row for each order and only the product name for which the condition is true (marked with an 'x' in the order row) are columns.
I thank in advance anyone who tries to solve this.

Using your transform query, you found out allProducts and allOrders. Then you can generate all combinations using CROSS JOIN.
Now you try to match each combination with the data already on transfrom, for every match you assign X.
Now with that data you can do a DINAMIC PIVOT. I skip because looks like you know how to do it.
SQL DEMO
WITH transform as (
select o.Id OrderId, o.Flag OrderFlag, p.Id ProductId,
p.Flag ProductFlag, p.Name ProductName
from TbOrder o
inner join TbProduct p
on (o.Flag & p.Flag) = p.Flag
), allProducts as (
SELECT distinct ProductName
FROM transform
), allOrders as (
SELECT distinct OrderFlag
FROM transform
)
SELECT O.OrderFlag,
P.ProductName,
CASE WHEN T.ProductName IS NOT NULL
THEN 'X'
END as flag
INTO partial_result
FROM allProducts P
CROSS JOIN allOrders O
LEFT JOIN transform T
ON O.OrderFlag = T.OrderFlag
AND P.ProductName= T.ProductName;
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.ProductName)
FROM partial_result c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #query = 'SELECT OrderFlag, ' + #cols + ' from
(
select OrderFlag
, ProductName
, flag
from partial_result
) x
pivot
(
max(flag)
for ProductName in (' + #cols + ')
) p ';
execute(#query);
OUTPUT

Related

Grouping with pivot to get count by week

I Have a table temp_customer. Schema and some data like below-
CREATE TABLE [dbo].[temp_customer](
[id] [int] IDENTITY(1,1) NOT NULL,
[company_id] [int] NOT NULL,
[created_by] [int] NULL,
[created_at] [datetime] NULL,
[code] [varchar](25) NOT NULL,
[name] [varchar](50) NULL,
)
SET IDENTITY_INSERT [dbo].[temp_customer] ON
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1714, 1, 1, CAST(N'2018-02-14 11:43:00.757' AS DateTime), N'STET-00001', N'Stephan Taylor')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1715, 1, 1, CAST(N'2018-02-14 11:43:01.007' AS DateTime), N'TAMJ-00001', N'Tamala Jones')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1716, 1, 2, CAST(N'2018-02-14 11:43:01.457' AS DateTime), N'TARB-00001', N'Taran Blauman')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1718, 1, 1, CAST(N'2019-01-29 00:00:00.000' AS DateTime), N'VERD-00001', N'Veronica Dave')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1719, 1, 1, CAST(N'2018-02-14 11:43:02.190' AS DateTime), N'WAYD-00001', N'Wayne Dotson')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1720, 1, 2, CAST(N'2018-03-12 07:40:34.107' AS DateTime), N'LARJ-00001', N'Larry Jacobs')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1721, 1, 2, CAST(N'2018-03-28 03:40:52.673' AS DateTime), N'ROBM-00002', N'Robert Matte')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1722, 1, 1, CAST(N'2018-03-28 05:09:53.093' AS DateTime), N'MART-00001', N'Mark Taylor')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1723, 1, 1, CAST(N'2018-03-28 05:39:19.237' AS DateTime), N'TAYT-00001', N'ALEX BRUZZI')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1724, 1, 3, CAST(N'2018-04-04 04:37:29.547' AS DateTime), N'STOCK', N'STOCK')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1725, 1, 3, CAST(N'2018-04-04 06:51:10.797' AS DateTime), N'AMAT-00001', N'Amanda Trezza')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1726, 1, 1, CAST(N'2018-04-04 06:55:04.720' AS DateTime), N'ADRG-00001', N'Adriana Grande')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1727, 1, 3, CAST(N'2018-04-05 00:00:00.000' AS DateTime), N'ISSJ-00002', N'Issac Johnes')
INSERT [dbo].[temp_customer] ([id], [company_id], [created_by], [created_at], [code], [name]) VALUES (1728, 1, 2, CAST(N'2019-01-18 00:00:00.000' AS DateTime), N'JACJ-00001', N'Jacob Jensen')
it looks like -
I would like to get output group on created_by with total_customer_created and week in which customer created as individual columns. eg in excel like -
i.e on basis of Week(starting from monday) , total customer created by 1,2,3..... etc in required date range.
Any helps appreciated in advance.
I have found one solution, it is working.
firstly a function to find weeks(with date range)
CREATE FUNCTION [dbo].[fGetWeeksList]
(
#StartDate DATETIME
,#EndDate DATETIME
)
RETURNS
TABLE
AS
RETURN
(
SELECT DATEADD(DAY,-(DATEPART(DW,DATEADD(WEEK, x.number, #StartDate))-2),DATEADD(WEEK, x.number, #StartDate)) as [StartDate]
,DATEADD(DAY,-(DATEPART(DW,DATEADD(WEEK, x.number + 1, #StartDate))-1) ,DATEADD(WEEK, x.number + 1, #StartDate)) AS [EndDate]
FROM master.dbo.spt_values x
WHERE x.type = 'P' AND x.number <= DATEDIFF(WEEK, #StartDate, DATEADD(WEEK,0,CAST(#EndDate AS DATE)))
)
And then use it in below query
select cast(cast(fGetWeeksList.startdate as date) as varchar(max)) + ' To '+cast(cast(fGetWeeksList.enddate as date) as varchar(max)) as week_range,
*
into #week_table from fGetWeeksList('01-01-2022','06-02-2022')
select users.user_cd ,
users.first_name ,
users.last_name,
count(customers.id) cust_count,
#week_table.week_range
into #cust_count
from users
inner join customers on
users.id = customers.created_by
inner join #week_table on
cast(customers.created_at as date) between #week_table.StartDate and #week_table.EndDate
group by
users.user_cd ,users.first_name ,users.last_name,
#week_table.week_range
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', ' + QUOTENAME(week_range)
FROM (SELECT distinct #week_table.week_range FROM #week_table
GROUP BY #week_table.week_range) AS x;
print #columns
SET #sql = N'SELECT user_cd,p.first_name,p.last_name, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT p.week_range, p.user_cd,p.first_name,p.last_name, p.cust_count FROM dbo.#cust_count AS p
) AS j
PIVOT
(
SUM(cust_count) FOR week_range IN ('+ STUFF(REPLACE(#columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT #sql;
EXEC sp_executesql #sql;
drop table #week_table
drop table #cust_count

A help In the Pivot Method

Help In the pivot method , i dont want to keep writing all the Id is there a way to Like Do it without writing all the id
I dont know how
SELECT 'Montant' AS IdClient,
*
FROM
(
SELECT MontantTransaction,IdClient
FROM Transactions
) AS TableSource
PIVOT
(
Sum(MontantTransaction)
FOR IdClient IN( [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24])
) AS TableDePivot;
i expect to see this code without the ( [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13]....
Try this -
Sample Temp Table & Data
Create Table #Transactions
(
IdClient varchar(3),
MontantTransaction decimal(10,2)
)
insert into #Transactions values (1, 1000.00)
insert into #Transactions values (1, 200.00)
insert into #Transactions values (2, 800.00)
insert into #Transactions values (2, 700.00)
insert into #Transactions values (3, 1100.00)
insert into #Transactions values (4, 1400.00)
Query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.IdClient)
FROM #Transactions c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ''Montant'' AS IdClient, ' + #cols + ' from
(
select
MontantTransaction
, IdClient
from #Transactions
) x
pivot
(
Sum(MontantTransaction)
for IdClient in (' + #cols + ')
) p '
execute(#query)
drop table #Transactions

How to make two column pivot and other as normal

I have 3 table name class , Student and Religion and below data are as follows
Class Table
ClassId ClassName
1 class-1
2 class-2
3 class-3
Religion Table
ReligionId RegionName
1 Hindu
2 Muslim
Student Table
employeeid StudentName religionid dateofbirth classid
1 A 1 1990-12-04 1
2 B 2 1999-12-04 2
3 C 2 2000-12-04 1
4 D 2 1988-12-04 1
5 E 2 2003-12-04 2
6 F NULL 2002-12-04 1
How Can I achieve below record from above tables
CLASSNAME HINDU MUSLIM Noreligion
class-1 1 2 1
class-2 0 2 0
You can create the tables from the below scripts
CREATE TABLE [dbo].[class](
[ClassId] [int] IDENTITY(1,1) NOT NULL,
[ClassName] [varchar](250) NULL,
CONSTRAINT [PK_class] PRIMARY KEY CLUSTERED
(
[ClassId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Religion](
[ReligionId] [int] NOT NULL,
[RegionName] [varchar](50) NULL,
CONSTRAINT [PK_Religion] PRIMARY KEY CLUSTERED
(
[ReligionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Student](
[employeeid] [int] IDENTITY(1,1) NOT NULL,
[StudentName] [varchar](150) NULL,
[religionid] [int] NULL,
[dateofbirth] [date] NULL,
[classid] [int] NULL,
CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED
(
[employeeid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[class] ON
INSERT [dbo].[class] ([ClassId], [ClassName]) VALUES (1, N'class-1')
INSERT [dbo].[class] ([ClassId], [ClassName]) VALUES (2, N'class-2')
INSERT [dbo].[class] ([ClassId], [ClassName]) VALUES (3, N'class-3')
SET IDENTITY_INSERT [dbo].[class] OFF
INSERT [dbo].[Religion] ([ReligionId], [RegionName]) VALUES (1, N'hindu')
INSERT [dbo].[Religion] ([ReligionId], [RegionName]) VALUES (2, N'muslim')
SET IDENTITY_INSERT [dbo].[Student] ON
INSERT [dbo].[Student] ([employeeid], [StudentName], [religionid], [dateofbirth], [classid]) VALUES (1, N'A', 1, CAST(N'1990-12-04' AS Date), 1)
INSERT [dbo].[Student] ([employeeid], [StudentName], [religionid], [dateofbirth], [classid]) VALUES (2, N'B', 2, CAST(N'1999-12-04' AS Date), 2)
INSERT [dbo].[Student] ([employeeid], [StudentName], [religionid], [dateofbirth], [classid]) VALUES (3, N'C', 2, CAST(N'2000-12-04' AS Date), 1)
INSERT [dbo].[Student] ([employeeid], [StudentName], [religionid], [dateofbirth], [classid]) VALUES (4, N'D', 2, CAST(N'1988-12-04' AS Date), 1)
INSERT [dbo].[Student] ([employeeid], [StudentName], [religionid], [dateofbirth], [classid]) VALUES (5, N'E', 2, CAST(N'2003-12-04' AS Date), 2)
INSERT [dbo].[Student] ([employeeid], [StudentName], [religionid], [dateofbirth], [classid]) VALUES (6, N'F', NULL, CAST(N'2002-12-04' AS Date), 1)
SET IDENTITY_INSERT [dbo].[Student] OFF
Do it require Pivot table to be use.
I was not able to made the query getting such records.
This is more conditional aggregation that pivoting. This gets you the result you're after:
SELECT C.ClassName,
COUNT(CASE R.RegionName WHEN 'Hindu' THEN 1 END) AS Hindu,
COUNT(CASE R.RegionName WHEN 'Muslim' THEN 1 END) AS Muslim,
COUNT(CASE WHEN R.RegionName IS NULL THEN 1 END) AS NoReligion
FROM dbo.class C
JOIN dbo.Student S ON C.ClassId = S.classid
LEFT JOIN dbo.Religion R ON S.religionid = R.ReligionId
GROUP BY C.ClassName;
If you don't understand the syntax, please ask.
Edit: OP has now stated that there are more religions than just the 2 they provided, and needs to be dynamic. This therefore gives:
--Additional sample row if you wish:
INSERT [dbo].[Religion] ([ReligionId], [RegionName])
VALUES (3, N'Catholic');
GO
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT C.ClassName,' + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(10) +
N' COUNT(CASE R.RegionName WHEN ' + QUOTENAME(R.RegionName,N'''') + N' THEN 1 END) AS ' + QUOTENAME(R.RegionName)
FROM dbo.Religion R
ORDER BY R.ReligionId
FOR XML PATH(N'')),1,2,N'') + N',' + NCHAR(10) +
N'COUNT(CASE WHEN R.RegionName IS NULL THEN 1 END) AS NoReligion' + NCHAR(10) +
N'FROM dbo.class C' + NCHAR(10) +
N' JOIN dbo.Student S ON C.ClassId = S.classid' + NCHAR(10) +
N' LEFT JOIN dbo.Religion R ON S.religionid = R.ReligionId' + NCHAR(10) +
N'GROUP BY C.ClassName;';
SELECT #SQL;
EXEC sp_executesql #SQL;
This is a Pivot with dynamic columns. You can have unknown number of Religions
DECLARE #cols AS NVARCHAR(MAX), #sql AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(ReligionName)
FROM Religion c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
Set #sql = '
SELECT ClassId, '+ #cols + ',[NoReligion]
FROM
(
Select
IIf (ReligionName IS NULL, ''NoReligion'', ReligionName) As ReligionName,
employeeid,s.ClassId
From
Student s INNER JOIN
Class ON s.classid = Class.ClassId FULL OUTER JOIN
Religion ON s.religionid = Religion.ReligionId) As src
Pivot
(
Count(employeeid)
FOR ReligionName IN('+#cols+',[NoReligion])
) As pvt'
EXECUTE sp_executesql #sql

Daily report of sales using Pivot table SQL server with multiple values under each date column

I have to send a weekly report to the Administrator from a website. The weekly report looks something like below image.
ATV (Average Transaction Value) and UPT (Units per transaction)
Table schema and sample data are given below
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sale](
[Id] [nvarchar](128) NOT NULL,
[UserId] [nvarchar](128) NOT NULL,
[StoreId] [nvarchar](128) NOT NULL,
[SaleAmount] [decimal](18, 2) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[Note] [nvarchar](max) NULL,
[ATV] [decimal](18, 2) NOT NULL DEFAULT ((0)),
[UPT] [decimal](18, 2) NOT NULL DEFAULT ((0)),
CONSTRAINT [PK_dbo.Sale] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object: Table [dbo].[Store] Script Date: 12-Jun-17 2:20:36 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Store](
[Id] [nvarchar](128) NOT NULL,
[Title] [nvarchar](1000) NOT NULL,
[Address1] [nvarchar](100) NULL,
[Address2] [nvarchar](100) NULL,
[Address3] [nvarchar](100) NULL,
[City] [nvarchar](100) NULL,
[State] [nvarchar](100) NULL,
[Country] [nvarchar](100) NULL,
[ZipCode] [nvarchar](100) NULL,
[Telephone1] [nvarchar](100) NULL,
[Telephone2] [nvarchar](100) NULL,
[Telephone3] [nvarchar](100) NULL,
[Location] [geography] NULL,
[IsActive] [bit] NOT NULL DEFAULT ((0)),
[Rank] [int] NOT NULL DEFAULT ((0)),
CONSTRAINT [PK_dbo.Store] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'11', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(9000.00 AS Decimal(18, 2)), CAST(N'2017-06-04 10:50:04.997' AS DateTime), N'5th', CAST(16.00 AS Decimal(18, 2)), CAST(27.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'12', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(8000.00 AS Decimal(18, 2)), CAST(N'2017-06-05 10:50:04.997' AS DateTime), N'4th', CAST(15.00 AS Decimal(18, 2)), CAST(26.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'13', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(7000.00 AS Decimal(18, 2)), CAST(N'2017-06-06 10:50:04.997' AS DateTime), N'3rd', CAST(14.00 AS Decimal(18, 2)), CAST(25.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'14', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(6000.00 AS Decimal(18, 2)), CAST(N'2017-06-07 10:50:04.997' AS DateTime), N'second', CAST(13.00 AS Decimal(18, 2)), CAST(24.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'15', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(5000.00 AS Decimal(18, 2)), CAST(N'2017-06-08 10:50:04.997' AS DateTime), N'TEST', CAST(12.00 AS Decimal(18, 2)), CAST(23.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'16', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(10000.00 AS Decimal(18, 2)), CAST(N'2017-06-09 10:50:04.997' AS DateTime), N'6th', CAST(17.00 AS Decimal(18, 2)), CAST(28.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Sale] ([Id], [UserId], [StoreId], [SaleAmount], [CreatedDate], [Note], [ATV], [UPT]) VALUES (N'17', N'9d5626d9-a71e-4116-bae5-4e6d736986c3', N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', CAST(888.00 AS Decimal(18, 2)), CAST(N'2017-06-10 10:43:49.693' AS DateTime), N'test test2', CAST(12.00 AS Decimal(18, 2)), CAST(13.00 AS Decimal(18, 2)))
GO
INSERT [dbo].[Store] ([Id], [Title], [Address1], [Address2], [Address3], [City], [State], [Country], [ZipCode], [Telephone1], [Telephone2], [Telephone3], [Location], [IsActive], [Rank]) VALUES (N'67586972-6694-444a-9426-a0e6e4066015', N'store 3', N'1', N'Unnamed Road', NULL, N'Richmond', N'England', N'United Kingdom', N'DL11 6RR', NULL, NULL, NULL, NULL, 1, 3)
GO
INSERT [dbo].[Store] ([Id], [Title], [Address1], [Address2], [Address3], [City], [State], [Country], [ZipCode], [Telephone1], [Telephone2], [Telephone3], [Location], [IsActive], [Rank]) VALUES (N'68ece12f-c3e7-4705-88eb-2a0da2d7c1cc', N'Test Product', N'tesadf', N'323', N'asdf', N'sdf23', N'234', N'United Kingdom', N'234', NULL, NULL, NULL, NULL, 1, 4)
GO
INSERT [dbo].[Store] ([Id], [Title], [Address1], [Address2], [Address3], [City], [State], [Country], [ZipCode], [Telephone1], [Telephone2], [Telephone3], [Location], [IsActive], [Rank]) VALUES (N'c71c82aa-2ad0-4599-b6d2-17a21a7b98da', N'Store 1', N'Greenhillstairs', NULL, NULL, N'Moffat', N'Scotland', N'United Kingdom', N'DG10 9SP', NULL, NULL, NULL, 0xE6100000010C5278753348B04B406FEE5465841C0CC0, 1, 1)
GO
INSERT [dbo].[Store] ([Id], [Title], [Address1], [Address2], [Address3], [City], [State], [Country], [ZipCode], [Telephone1], [Telephone2], [Telephone3], [Location], [IsActive], [Rank]) VALUES (N'f26f67f1-e8f7-44a4-aaac-e861d18d54f3', N'Store 2', N'Lythe Fell Road', NULL, NULL, NULL, N'England', N'United Kingdom', NULL, NULL, NULL, NULL, 0xE6100000010C640D72721A054B40729472ADACD303C0, 1, 2)
GO
Below pivot query
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
declare #fromDate AS NVARCHAR(MAX)
set #fromDate=CAST('2017-06-04 10:50:04.997' AS DATE)
SELECT CAST(CreatedDate AS DATE) [Date], sum(saleamount) [SaleTotal], ATV,UPT
INTO #PivotSalesData2
FROM sale
where createddate>='2017-06-04 10:50:04.997'
GROUP BY CAST(Createddate AS DATE),storeid,ATV,UPT
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME([Date])
FROM #PivotSalesData2
print #columnName
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
N'SELECT * from (SELECT (select Title from store where id=storeid ) storeid, CAST(CreatedDate AS DATE) [Date],
sum(atv) [atv]
FROM Sale
where createddate>=#fromDate
GROUP BY CAST(CreatedDate AS DATE),storeid,atv) AS DailyData
PIVOT( sum([atv])
FOR [Date] IN (' + #ColumnName + ')) AS PVTTable'
print #DynamicPivotQuery
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery , N'#fromDate nvarchar(max)', #fromDate = #fromDate
Generate following output
enter image description here
But I need ATV and UPT column values under each date column
This I have tested with your sample data.
Let me know the final output that you are looking for and you output and input should in tandem.
SET #DynamicPivotQuery =
N'
SELECT * from
(select UserId,sum( [ATV])atv
,DATENAME(dw,CreatedDate) createddate
FROM #Sale
group by userid,createddate
) AS DailyData
PIVOT( sum(atv)
FOR createddate IN ('+#ColumnName+')
) AS PVTTable
union ALL
SELECT * from
(select UserId,sum( [UPT])[UPT]
,DATENAME(dw,CreatedDate) createddate
FROM #Sale
group by userid,createddate
) AS DailyData
PIVOT( sum(upt)
FOR createddate IN ('+#ColumnName+')
) AS PVTTable
'
print #DynamicPivotQuery
exec (#DynamicPivotQuery)

Pivoting without aggregation

I'm trying to pivot without aggregation, and running into a bit of a wall.
Here's the sample T-SQL I'm trying to get to work:
declare #optionalFields table (ParentId int, Name nvarchar(50), Value nvarchar(50));
insert into #optionalFields values (1, 'Field1', 'Foo');
insert into #optionalFields values (1, 'Field2', 'Bar');
insert into #optionalFields values (1, 'Field3', '42');
insert into #optionalFields values (2, 'Field1', 'Bar');
insert into #optionalFields values (2, 'Field2', 'Foo');
insert into #optionalFields values (2, 'Field3', '24');
declare #data table (Id int, Name nvarchar(50));
insert into #data values (1, 'Test record 1');
insert into #data values (2, 'Test record 2');
declare #joined table (Id int, Name nvarchar(50), OptionalFieldName nvarchar(50), OptionalFieldValue nvarchar(50));
insert into #joined
select
data.Id
,data.Name
,opt.Name
,opt.Value
from #data data
inner join #optionalFields opt on data.Id = opt.ParentId
declare #cols as nvarchar(max) =
stuff((select distinct ',' + quotename(OptionalFieldName) from #joined for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '');
select * into #tmp from #joined
-- just to see that it's returning the expected values (it does)
select
Id
,Name
,OptionalFieldName
,OptionalFieldValue
,row_number() over (partition by Id order by Id) RN
from #tmp -- this is the FROM clause in the below dynamic-sql query
declare #query as nvarchar(max) = '
select Id, Name, ' + #cols + '
from (select Id, Name, OptionalFieldName, OptionalFieldValue, row_number() over (partition by Id order by Id) RN from #tmp) src
pivot (max(OptionalFieldName) for RN in (' + #cols + ')) pvt';
execute(#query);
drop table #tmp;
SSMS is giving me 2 errors:
Msg 8114, Level 16, State 1, Line 4
Error converting data type nvarchar to bigint.
Msg 473, Level 16, State 1, Line 4
The incorrect value "Field1" is supplied in the PIVOT operator.
The "debug" select statement is returning this:
The article (link above) seemed very promising, however I can't seem to be able to get it to work. What am I doing wrong? Or is this article outright wrong and what I'm trying to do is impossble?
I've seen a number of similar SO questions, but either they involved all-numeric fields that could "just work" with aggregation, or they involved known columns that could be implemented as simple joins - I don't know what OptionalFieldName values I'm going to be selecting, and the OptionalFieldValue values are strings that simply can't be aggregated, at least AFAIK.
I'm a bit confused on why you are trying to trick this using row_number(). Even though you have string values, you can still aggregate it - you just need to use max or min to get the result.
I'd always recommend trying to write your query with hard-coded values first, especially when using PIVOT before even attempting to use dynamic SQL. I'm unsure why you can't just write the query this way:
select Id, Name, Field1, Field2, Field3
from
(
select
Id
,Name
,OptionalFieldName
,OptionalFieldValue
from #tmp
) d
pivot
(
max(OptionalFieldValue)
for OptionalFieldName in (Field1, Field2, Field3)
) piv;
See a Demo.
Then if you really need dynamic SQL, you would just write it:
declare #optionalFields table (ParentId int, Name nvarchar(50), Value nvarchar(50));
insert into #optionalFields values (1, 'Field1', 'Foo');
insert into #optionalFields values (1, 'Field2', 'Bar');
insert into #optionalFields values (1, 'Field3', '42');
insert into #optionalFields values (2, 'Field1', 'Bar');
insert into #optionalFields values (2, 'Field2', 'Foo');
insert into #optionalFields values (2, 'Field3', '24');
declare #data table (Id int, Name nvarchar(50));
insert into #data values (1, 'Test record 1');
insert into #data values (2, 'Test record 2');
declare #joined table (Id int, Name nvarchar(50), OptionalFieldName nvarchar(50), OptionalFieldValue nvarchar(50));
insert into #joined
select
data.Id
,data.Name
,opt.Name
,opt.Value
from #data data
inner join #optionalFields opt on data.Id = opt.ParentId
declare #cols as nvarchar(max);
set #cols = stuff((select distinct ',' + quotename(OptionalFieldName)
from #joined
for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '');
select * into #tmp from #joined
DECLARE #query AS NVARCHAR(MAX)
set #query = 'SELECT Id, Name,' + #cols + '
from
(
select Id
,Name
,OptionalFieldName
,OptionalFieldValue
from #tmp
) x
pivot
(
max(OptionalFieldValue)
for OptionalFieldName in (' + #cols + ')
) p '
execute(#query);
See Demo. Both versions appear to give the result that you have requested.
EDIT: This answer is here only to show another way to accomplish this pivoting. The answer from #bluefeet is the best solution!
Hope I understand what you need right:
declare #optionalFields table (ParentId int, Name nvarchar(50), Value nvarchar(50));
insert into #optionalFields values (1, 'Field1', 'Foo');
insert into #optionalFields values (1, 'Field2', 'Bar');
insert into #optionalFields values (1, 'Field3', '42');
insert into #optionalFields values (2, 'Field1', 'Bar');
insert into #optionalFields values (2, 'Field2', 'Foo');
insert into #optionalFields values (2, 'Field3', '24');
declare #data table (Id int, Name nvarchar(50));
insert into #data values (1, 'Test record 1');
insert into #data values (2, 'Test record 2');
select
data.Id
,data.Name
,opt.Name as Name1
,opt.Value into #tmp
from #data data
inner join #optionalFields opt on data.Id = opt.ParentId
declare #cols as nvarchar(max) =
stuff((select distinct ',' + quotename(Name1) from #tmp for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '');
DECLARE #cols1 as nvarchar(max) =
stuff((select distinct +',MAX(CASE WHEN (pvt1.'+quotename(Name1) +' = ros.RN AND pvt1.id = ros.id) THEN ros.Value ELSE NULL END) as '+quotename(Name1) from #tmp for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '');
declare #query as nvarchar(max) = '
;WITH cte AS(
SELECT * FROM #tmp
),
ros AS (
SELECT ROW_NUMBER() OVER (partition by Id order by Id) AS [RN],id,Value
FROM cte),
pvt1 AS (
select *
from (select Id, Name, Name1, row_number() over (partition by Id order by Id) RN
from cte) src
pivot (max(RN) for Name1 in ('+#cols+')) pvt)
SELECT pvt1.ID,
pvt1.Name,
'+#cols1+'
FROM pvt1
CROSS JOIN ros
GROUP BY pvt1.ID,
pvt1.Name'
execute(#query);
drop table #tmp
Result:
ID Name Field1 Field2 Field3
1 Test record 1 Foo Bar 42
2 Test record 2 Bar Foo 24
And if you add more Fields like insert into #optionalFields values (2, 'Field4', '15');, you will get:
ID Name Field1 Field2 Field3 Field4
1 Test record 1 Foo Bar 42 NULL
2 Test record 2 Bar Foo 24 15

Resources