Eliminate row in XML based on criteria - sql-server

here's the script to create the needed data:
CREATE TABLE [dbo].[TestXML](
[ID] [int] NOT NULL,
[PID] [int] NULL,
[Code] [int] NULL,
[Col1] [int] NULL,
[Col2] [int] NULL,
[Col3] [decimal](6, 2) NULL,
[Col4] [decimal](6, 2) NULL,
[Col5] [int] NULL,
CONSTRAINT [PK_TestXML] PRIMARY KEY CLUSTERED ([ID] ASC)
)
GO
CREATE TABLE [dbo].[XML_Columns_Reference](
[TableName] nvarchar(10) NULL,
[TableNameXML] nvarchar(10) NULL,
[ColumnName] nvarchar(10) NULL,
[ColumnNameXML] nvarchar(10) NULL,
[ColumnOrder] [int] NULL,
[GroupName] nvarchar(10) NULL,
[GroupOrder] [int] NULL,
[Category] [int] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[XML_NoUseCols_Ref](
[TableNameXML] nvarchar(10) NULL,
[Code] [int] NULL,
[ColumnName] nvarchar(10) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[TestXML] ([ID], [PID], [Code], [Col1], [Col2], [Col3], [Col4], [Col5]) VALUES (1, 1000, 10, 1, 2, CAST(0.20 AS Decimal(6, 2)), CAST(0.10 AS Decimal(6, 2)), 1)
INSERT [dbo].[TestXML] ([ID], [PID], [Code], [Col1], [Col2], [Col3], [Col4], [Col5]) VALUES (2, 1000, 20, NULL, 1, CAST(1.00 AS Decimal(6, 2)), CAST(1.00 AS Decimal(6, 2)), 1)
INSERT [dbo].[TestXML] ([ID], [PID], [Code], [Col1], [Col2], [Col3], [Col4], [Col5]) VALUES (3, 1000, 30, NULL, NULL, CAST(2.00 AS Decimal(6, 2)), CAST(2.00 AS Decimal(6, 2)), 5)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col1', N'N', 1, N'A', 2, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col2', N'V', 2, N'A', 2, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col3', N'N', 1, N'B', 3, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col4', N'V', 2, N'B', 3, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col5', N'A', 1, N'C', 1, NULL)
INSERT [dbo].[XML_NoUseCols_Ref] ([TableNameXML], [Code], [ColumnName]) VALUES (N'T', 20, N'Col1')
INSERT [dbo].[XML_NoUseCols_Ref] ([TableNameXML], [Code], [ColumnName]) VALUES (N'T', 30, N'Col1')
INSERT [dbo].[XML_NoUseCols_Ref] ([TableNameXML], [Code], [ColumnName]) VALUES (N'T', 30, N'Col2')
Here's the query I run:
DECLARE #PID int
SET #PID=1000
SELECT
GroupName as [#n],
(SELECT
Code [#n],
(SELECT
ColumnNameXML as [col/#n],
CASE name
WHEN 'Col1' THEN ISNULL(Col1,0)
WHEN 'Col2' THEN ISNULL(Col2,0)
WHEN 'Col3' THEN ISNULL(Col3,0)
WHEN 'Col4' THEN ISNULL(Col4,0)
WHEN 'Col5' THEN ISNULL(Col5,0)
END AS [col/col_value]
FROM sys.columns
CROSS JOIN TestXML ls1
INNER JOIN XML_Columns_Reference r1
ON sys.columns.name=r1.columnname
WHERE object_id = OBJECT_ID('TestXML') and r1.TableNameXML='T'
and ls1.PID=#PID and ls1.ID=ls2.ID and r1.GroupName=r2.GroupName
and r1.ColumnName NOT IN (SELECT [ColumnName]
FROM XML_NoUseCols_Ref
WHERE TableNameXML='T' and [Code]=ls1.Code
GROUP BY ColumnName)
ORDER BY column_id
FOR XML PATH(''),TYPE
)
FROM TestXML ls2
WHERE ls2.PID=#PID
FOR XML PATH('cat'),TYPE
)
FROM sys.columns
CROSS JOIN TestXML ls3
INNER JOIN XML_Columns_Reference r2
ON sys.columns.name=r2.columnname
WHERE object_id = OBJECT_ID('TestXML') and ls3.PID=#PID and r2.TableNameXML='T'
GROUP BY GroupName
ORDER BY MIN(groupOrder)
FOR XML PATH('grp'),TYPE
Result:
What I need is when there is a reference in XML_NoUseCols_Ref for all the rows of a group (you can get group in XML_Columns_Reference) to eliminated the cat row in the XML.
In the example that would be cat n="30" in grp n="A"
Any kind of help would be appreciated.
Thank you.

Instead of repeating the logic in many places I'd suggest to use a CTE (something like an ad-hoc VIEW) to pre-fetch your data. The rest is rather simple nesting with correlated sub-queries and much better to read:
Hope I got your logic correctly...
WITH cte AS
(
SELECT ls1.ID,ls1.PID,ls1.Code
,r1.ColumnNameXML,r1.GroupName,r1.GroupOrder
,CASE name
WHEN 'Col1' THEN ISNULL(Col1,0)
WHEN 'Col2' THEN ISNULL(Col2,0)
WHEN 'Col3' THEN ISNULL(Col3,0)
WHEN 'Col4' THEN ISNULL(Col4,0)
WHEN 'Col5' THEN ISNULL(Col5,0)
END AS ColumnValue
FROM sys.columns
CROSS JOIN TestXML ls1
INNER JOIN XML_Columns_Reference r1
ON sys.columns.name=r1.columnname
WHERE object_id = OBJECT_ID('TestXML') and r1.TableNameXML='T'
and ls1.PID=#PID
and r1.ColumnName NOT IN ( SELECT [ColumnName]
FROM XML_NoUseCols_Ref
WHERE TableNameXML='T' and [Code]=ls1.Code
GROUP BY ColumnName)
)
SELECT GroupName AS [#n]
,(
SELECT Code AS [#n]
,(
SELECT cte3.ColumnNameXML AS [#n]
,cte3.ColumnValue AS [col_value]
FROM cte cte3
WHERE cte3.GroupName=cte1.GroupName AND cte3.Code=cte2.Code
ORDER BY cte3.ColumnNameXML
FOR XML PATH('col'),TYPE
)
FROM cte cte2
WHERE cte1.GroupName=cte2.GroupName
GROUP BY cte2.Code
ORDER BY cte2.Code
FOR XML PATH('cat'),TYPE
)
FROM cte cte1
GROUP BY GroupName,GroupOrder
ORDER BY GroupOrder
FOR XML PATH('grp');

Related

Getting error Attempting to set a non-NULL-able column's value to NULL while insert into in temp table

Below is the query where I am getting error
Declare #WorldpayAccountKeys varchar(max)='9132E282-2602-4D54-86CF-C93F9A56CF34
,E3759AFF-6968-40C1-8ABD-A25AE9176C1A
,B276D9C8-CC13-47C8-A469-76F8946AF6C0
,BCE689AD-CDC4-42D1-8718-69902ACCA9C3
,BCE689AD-CDC4-42D1-8718-69902ACCA9C4'
SELECT fooAccountId as abc, T.RowNum, T.Value
into #temp
FROM
(
SELECT O.Value, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) as RowNum
FROM string_split(#WorldpayAccountKeys,',') O
) T
LEFT JOIN
foo R ON R.fooKey= T.Value
AND (R.foocId IN (11,12,13,14))
AND R.fooIndex = 0
I know error is for column fooAccountId which is primary key not null, I am getting one null record from this query for column fooAccountId
I have tried, applying null to primary key but it inserted intemp table , why not with above query
select fooAccountId as abc into #b from foo
union all
select null
Needed help, using sql server 2017
Sample query getting error:
CREATE TABLE [dbo].[WA](
[WAid] [bigint] IDENTITY(1,1) NOT NULL,
[WAKey] [uniqueidentifier] NOT NULL,
[WATypeRefKey] [char](1) NOT NULL,
[AccountId] [varchar](111) NULL,
[AccountToken] [varchar](111) NULL,
[AcceptorId] [varchar](111) NULL,
[ApplicationId] [varchar](111) NULL,
[ClientId] [int] NOT NULL,
[Version] [int] NOT NULL,
[VersionOn] [datetimeoffset](7) NOT NULL,
[VersionBy] [varchar](111) NOT NULL,
[RemovedIndex] [smallint] NOT NULL,
CONSTRAINT [WA_PKey] PRIMARY KEY CLUSTERED
(
[WAid] 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 IDENTITY_INSERT [dbo].[WA] ON
GO
INSERT [dbo].[WA] ([WAid], [WAKey], [WATypeRefKey], [AccountId], [AccountToken], [AcceptorId], [ApplicationId], [ClientId], [Version], [VersionOn], [VersionBy], [RemovedIndex]) VALUES (1, N'9132e282-2602-4d54-86cf-c93f9a56cf34', N'Y', N'11', N'11', N'11', N'11', 11, 1, CAST(N'2022-11-30T00:00:00.0000000+00:00' AS DateTimeOffset), N'test', 0)
GO
INSERT [dbo].[WA] ([WAid], [WAKey], [WATypeRefKey], [AccountId], [AccountToken], [AcceptorId], [ApplicationId], [ClientId], [Version], [VersionOn], [VersionBy], [RemovedIndex]) VALUES (3, N'e3759aff-6968-40c1-8abd-a25ae9176c1a', N'Y', N'12', N'12', N'12', N'12', 12, 1, CAST(N'2022-12-01T18:14:11.5300000+00:00' AS DateTimeOffset), N'Test', 0)
GO
INSERT [dbo].[WA] ([WAid], [WAKey], [WATypeRefKey], [AccountId], [AccountToken], [AcceptorId], [ApplicationId], [ClientId], [Version], [VersionOn], [VersionBy], [RemovedIndex]) VALUES (6, N'b276d9c8-cc13-47c8-a469-76f8946af6c0', N'Y', N'13', N'13', N'13', N'13', 13, 1, CAST(N'2022-12-01T23:02:40.3164474+05:30' AS DateTimeOffset), N'Test', 0)
GO
INSERT [dbo].[WA] ([WAid], [WAKey], [WATypeRefKey], [AccountId], [AccountToken], [AcceptorId], [ApplicationId], [ClientId], [Version], [VersionOn], [VersionBy], [RemovedIndex]) VALUES (8, N'bce689ad-cdc4-42d1-8718-69902acca9c3', N'Y', N'134', N'14', N'14', N'14', 14, 1, CAST(N'2022-12-01T23:04:04.8758186+05:30' AS DateTimeOffset), N'Test', 0)
GO
INSERT [dbo].[WA] ([WAid], [WAKey], [WATypeRefKey], [AccountId], [AccountToken], [AcceptorId], [ApplicationId], [ClientId], [Version], [VersionOn], [VersionBy], [RemovedIndex]) VALUES (11, N'bce689ad-cdc4-42d1-8718-69902acca9c4', N'Y', N'135', N'15', N'15', N'15', 15, 1, CAST(N'2022-12-06T08:25:23.3533330+00:00' AS DateTimeOffset), N'Test', 0)
GO
Declare #WorldpayAccountKeys varchar(max)='9132E282-2602-4D54-86CF-C93F9A56CF34
,E3759AFF-6968-40C1-8ABD-A25AE9176C1A
,B276D9C8-CC13-47C8-A469-76F8946AF6C0
,BCE689AD-CDC4-42D1-8718-69902ACCA9C3
,BCE689AD-CDC4-42D1-8718-69902ACCA9C4'
drop table #temp
SELECT [WAid] as abc, T.RowNum, T.Value
into #temp
FROM
(
SELECT O.Value, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) as RowNum
FROM string_split(#WorldpayAccountKeys,',') O
) T
LEFT JOIN
[WA] R ON R.[WAKey]= T.Value
AND (R.ClientId IN (11,12,13,14))
AND R.RemovedIndex = 0
The table that this SELECT INTO automatically creates is
CREATE TABLE #temp(
[abc] [bigint] IDENTITY(1,1) NOT NULL,
[RowNum] [bigint] NULL,
[Value] [varchar](max) NULL
)
The copying over of the IDENTITY property is probably causing the problem as this will require the column to be NOT NULL.
The reality is that the output of this column can be null in your query due to the outer join so not compatible with IDENTITY (which requires the NOT NULL).
You can suppress this copying over of the property by doing a no-op calculation to the column.
e.g.
SELECT [WAid]+0 as abc
instead of
SELECT [WAid] as abc
The resultant table definition is
CREATE TABLE #temp(
[abc] [bigint] NULL,
[RowNum] [bigint] NULL,
[Value] [varchar](max) NULL
)

How to exclude same rows in SELECT

I have this script that creates a table and store Sale Order information. The scenario behind it is that once and Item is added into Sale Order it's Status is 'A' means Add. Later somehow customer wants that item to be removed so we add a new row with same details but Status as 'D' means Delete.
Now I want to get only active Sale Order Items which should not include that item which was Added and then Removed from Order.
Here's my script.
CREATE TABLE [dbo].[SALE_DETAIL](
[ORDER_NUMBER] [varchar](50) NULL,
[ITEM_NAME] [varchar](250) NULL,
[QUANTITY] [int] NULL,
[PRICE] [numeric](18, 0) NULL,
[Status] [varchar](50) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
INSERT [dbo].[SALE_DETAIL] ([ORDER_NUMBER], [ITEM_NAME], [QUANTITY], [PRICE], [Status]) VALUES (N'SO-100-ORD-19', N'Double Bed', 5, CAST(70000 AS Numeric(18, 0)), N'A')
GO
INSERT [dbo].[SALE_DETAIL] ([ORDER_NUMBER], [ITEM_NAME], [QUANTITY], [PRICE], [Status]) VALUES (N'SO-100-ORD-19', N'Sofa', 5, CAST(10000 AS Numeric(18, 0)), N'A')
GO
INSERT [dbo].[SALE_DETAIL] ([ORDER_NUMBER], [ITEM_NAME], [QUANTITY], [PRICE], [Status]) VALUES (N'SO-100-ORD-19', N'Dining Table', 1, CAST(50000 AS Numeric(18, 0)), N'A')
GO
INSERT [dbo].[SALE_DETAIL] ([ORDER_NUMBER], [ITEM_NAME], [QUANTITY], [PRICE], [Status]) VALUES (N'SO-100-ORD-19', N'Sofa', 5, CAST(10000 AS Numeric(18, 0)), N'D')
GO
The expected output I'm looking for should be something like this as Item 'Sofa' was cancelled from Order.
ORDER_NUMBER ITEM_NAME QTY PRICE
SO-100-ORD-19 Dining Table 1 50000
SO-100-ORD-19 Double Bed 5 70000
Query:
SELECT ORDER_NUMBER, ITEM_NAME, QUANTITY, PRICE FROM [dbo].[SALE_DETAIL]
WHERE Status <> 'D'
GROUP BY ORDER_NUMBER, ITEM_NAME, QUANTITY, PRICE
I would use NOT EXISTS:
SELECT SD.ORDER_NUMBER,
SD.ITEM_NAME,
SD.QUANTITY,
SD.PRICE
FROM dbo.[SALE_DETAIL] SD
WHERE NOT EXISTS (SELECT 1
FROM dbo.[SALE_DETAIL] e
WHERE e.ORDER_NUMBER = SD.ORDER_NUMBER
AND e.ITEM_NAME = SD.ITEM_NAME
AND e.[Status] = 'D');
Logically, the set-based answer is to use EXCEPT:
declare #SALE_DETAIL table([ORDER_NUMBER] [varchar](50) NULL,
[ITEM_NAME] [varchar](250) NULL,
[QUANTITY] [int] NULL,[PRICE] [numeric](18, 0) NULL,[Status] [varchar](50) NULL)
INSERT #SALE_DETAIL ([ORDER_NUMBER], [ITEM_NAME], [QUANTITY], [PRICE], [Status]) VALUES
(N'SO-100-ORD-19', N'Double Bed', 5, CAST(70000 AS Numeric(18, 0)), N'A'),
(N'SO-100-ORD-19', N'Sofa', 5, CAST(10000 AS Numeric(18, 0)), N'A'),
(N'SO-100-ORD-19', N'Dining Table', 1, CAST(50000 AS Numeric(18, 0)), N'A'),
(N'SO-100-ORD-19', N'Sofa', 5, CAST(10000 AS Numeric(18, 0)), N'D')
select Order_number,Item_name,Quantity,Price
from #SALE_DETAIL
where Status = 'A'
except
select Order_number,Item_name,Quantity,Price
from #SALE_DETAIL
where Status = 'D'
Which produces the results you've asked for. However, note that for whetever reason, this often seems to perform poorly in practice, in which case something like Larnu's Answer may be preferred.
In words: select all 'A'-records for which no matching 'D'-record exists.
In SQL:
SELECT ORDER_NUMBER, ITEM_NAME, QUANTITY, PRICE
FROM [dbo].[SALE_DETAIL] X
WHERE Status = 'A'
AND NOT EXISTS (
SELECT 1
FROM [dbo].[SALE_DETAIL] Y
WHERE Y.Status = 'D'
AND Y.ORDER_NUMBER = X.ORDER_NUMBER
AND Y.ITEM_NAME = X.ITEM_NAME
)
You can try get expected result using not in operator as shown below.
SELECT DISTINCT A.ORDER_NUMBER, A.ITEM_NAME,A.QUANTITY, A.PRICE, A.Status
FROM SALE_DETAIL A
where A.ITEM_NAME not in (select s.ITEM_NAME from SALE_DETAIL s
where s.[Status] = 'D')
The output is as shown below
ORDER_NUMBER ITEM_NAME QUANTITY PRICE Status
------------------------------------------------------
SO-100-ORD-19 Dining Table 1 50000 A
SO-100-ORD-19 Double Bed 5 70000 A
You can find the live demo Live Demo Here

how can I create Pivot temp table for month and year like calender

I want to create a temp table maybe using pivot for month and year as column.
I mentioned the question and solution for the pivot
Summarising the months data using pivot
CREATE TABLE [dbo].[Table1]([PID] [int] NULL,[ProductDesc] [nvarchar](50) NULL,[ProductCode] [nvarchar](10) NULL) ON [PRIMARY]
CREATE TABLE [dbo].[Table2]([Date] [varchar](50) NULL,[PID] [int] NULL) ON [PRIMARY]
---insert script---
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode]) VALUES (1, N'Packet-Eye', N'P001')
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode]) VALUES (2, N'Wiggy', N'W099 ')
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode]) VALUES (3, N'Wimax-Lite', N'W001')
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode]) VALUES (4, N'Wimax-Home', N'e W002 ')
INSERT [dbo].[Table2] ([Date], [PID]) VALUES (N'1/14/2009 ', 1)
INSERT [dbo].[Table2] ([Date], [PID]) VALUES (N'1/15/2009 ', 1)
INSERT [dbo].[Table2] ([Date], [PID]) VALUES (N'2/1/2009', 2)
INSERT [dbo].[Table2] ([Date], [PID]) VALUES (N'3/3/2009', 3)
GO
SELECT *
FROM
(
SELECT t1.productdesc as pd,COUNT(month(t2.date))as dates,
DateName( month , DateAdd( month , MONTH(t2.date) , 0 ) - 1 ) as mon
FROM table1 t1 inner join table2 t2 on t1.pid=t2.pid
where year(date) between 2009
and 2010 group by productdesc,month(t2.date),month (t2.date)
) AS D
PIVOT
(
sum(dates)
FOR mon IN( [January],[February],[March],[April],[May],[June],[July],[August],[September],[October],[November],[December])
) AS P

Nesting and ordering by largest to smallest amounts for multiple nest levels in XML

I have the following tables:
CREATE TABLE [dbo].[Amounts](
[EmpID] [int] NULL,
[Amount] [smallmoney] NULL
)
GO
CREATE TABLE [dbo].[Employees](
[LastName] [varchar](30) NULL,
[FirstName] [varchar](20) NULL,
[LocationID] [int] NULL,
[EmpID] [int] IDENTITY(1,1) NOT NULL
)
GO
CREATE TABLE [dbo].[Locations](
[LocationID] [int] NOT NULL,
[City] [varchar](20) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (7, 4750.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (2, 15750.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (7, 18100.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (4, 21000.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (3, 18100.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (10, 41000.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (7, 25000.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (11, 21500.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (5, 9900.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (7, 95900.0000)
GO
INSERT [dbo].[Amounts] ([EmpID], [Amount]) VALUES (9, 55000.0000)
GO
SET IDENTITY_INSERT [dbo].[Employees] ON
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Andrews', N'Alex', 1, 1)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Brown', N'Barry', 1, 2)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Jones', N'Lee', 2, 3)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Kendal', N'David', 1, 4)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Birch', N'Eric', 1, 5)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Kircher', N'Lisa', 4, 6)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Williams', N'David', 1, 7)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Marshall', N'John', NULL, 8)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Howard', N'James', 2, 9)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'O''Donnell', N'Terry', 2, 10)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Smythe', N'Sally', 1, 11)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Donovan', N'Barbara', 4, 12)
GO
INSERT [dbo].[Employees] ([LastName], [FirstName], [LocationID], [EmpID]) VALUES (N'Wagner', N'Phil', 1, 13)
GO
SET IDENTITY_INSERT [dbo].[Employees] OFF
GO
INSERT [dbo].[Locations] ([LocationID], [City]) VALUES (1, N'Paris')
GO
INSERT [dbo].[Locations] ([LocationID], [City]) VALUES (2, N'Sydney')
GO
INSERT [dbo].[Locations] ([LocationID], [City]) VALUES (3, N'Chicago')
GO
INSERT [dbo].[Locations] ([LocationID], [City]) VALUES (4, N'London')
GO
I want to generate XML which is ordered by the city which contains the highest overall amount first and then, nested within that, each employee (ordered by those with the highest total amount first) and then nested within each employee their amounts (highest first).
The following query (rather complex - please let me know if there is a simpler/cheaper way) gives the right ordering but I am stuck on how to get the XML(Elements) nesting as I have described.
;
WITH cte as
(
SELECT City,
FirstName,
LastName,
Amount,
SUM(Amount)OVER(PARTITION BY CONCAT(LastName, FirstName) ORDER BY CONCAT(LastName, FirstName) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS Total
FROM Locations l
INNER JOIN Employees e
ON l.LocationID = e.LocationID
INNER JOIN Amounts a
ON a.EmpID = e.EmpID
GROUP BY City, LastName, FirstName, Amount
)
SELECT City, FirstName,LastName,Amount
FROM cte
ORDER BY SUM(Total)OVER(PARTITION BY City ORDER BY Total DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) DESC, Total DESC, Amount DESC
Here's a simpler looking query giving the same results:
SELECT City,
FirstName,
LastName,
Amount
FROM Locations l
INNER JOIN Employees e
ON l.LocationID = e.LocationID
INNER JOIN Amounts a
ON a.EmpID = e.EmpID
GROUP BY City, LastName, FirstName, Amount
order by city,SUM(Amount)OVER(PARTITION BY CONCAT(LastName, FirstName) ORDER BY CONCAT(LastName, FirstName) ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) desc,Amount desc, firstname, lastname
SQLFiddle

Replicate records from exist version to new version in sql server

I have a table with some rows with version number 1 these rows have their
respective Parent Id if parent id is null then it is parent other wise
child with parent id, and I want to write query to copy all rows
from version number 1 to 2 and insert new rows with new respective parentid.
Below is my table and some data script.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Menu](
[MenuId] [bigint] IDENTITY(1,1) NOT NULL,
[MenuName] [nvarchar](50) NULL,
[ParentId] [bigint] NULL,
[VersionNumber] [bigint] NULL,
CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED
(
[MenuId] 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 IDENTITY_INSERT [dbo].[Menu] ON
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (1, N'Customer', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (2, N'Home', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (3, N'About', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (4, N'Add Customer', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (5, N'Administration', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (6, N'Edit Customer', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (7, N'Tenant', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (8, N'Manage Contact', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (9, N'Users', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (10, N'Customer List', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (11, N'Contact', NULL, 1)`enter code here`
SET IDENTITY_INSERT [dbo].[Menu] OFF
Thanks in advance.
I have a feeling there is more to the issue then what I am reading, but if you just want to duplicate the data and change the version number from 1 to 2, then this will work.
INSERT INTO dbo.Menu
( MenuName,
ParentId,
VersionNumber )
SELECT m.MenuName,
m.ParentId,
2
FROM Menu AS m
WHERE m.VersionNumber = 1
This one was a little tricky.
But below is a working solution.
The "MERGE" with the output values and original values (getting both types of values into the #Holder table) is the trick.
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Menu' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Menu]
END
GO
CREATE TABLE [dbo].[Menu](
[MenuId] [bigint] IDENTITY(1,1) NOT NULL,
[MenuName] [nvarchar](50) NULL,
[ParentId] [bigint] NULL,
[VersionNumber] [bigint] NULL,
CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED
(
[MenuId] 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 IDENTITY_INSERT [dbo].[Menu] ON
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (1, N'Customer', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (2, N'Home', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (3, N'About', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (4, N'Add Customer', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (5, N'Administration', NULL, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (6, N'Edit Customer', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (7, N'Tenant', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (8, N'Manage Contact', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (9, N'Users', 5, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (10, N'Customer List', 1, 1)
INSERT [dbo].[Menu] ([MenuId], [MenuName], [ParentId], [VersionNumber]) VALUES (11, N'Contact', NULL, 1)
SET IDENTITY_INSERT [dbo].[Menu] OFF
select * from [dbo].[Menu]
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
/* The "mapping values" holder/tracking table */
CREATE TABLE #Holder
(
--SurrogateKeyIDENTITY int not null IDENTITY (1,1) ,
OriginalMenuId [bigint] NULL,
OriginalParentId [bigint] NULL,
NewMenuSurrogateKey int null ,
NewParentIdSurrogateKey int null
)
/* This is the key trick. You need to do the INSERT and keep track of old and new surrogate keys. The MERGE trick is the only way to get values into the #holder...combining "output" values and original values */
MERGE INTO [dbo].[Menu] pc
USING [dbo].[Menu] AS sourceTable
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT([MenuName], [VersionNumber])
Values([MenuName] , [VersionNumber] + 1 ) /* Here is your "plus one" for the Version */
Output sourceTable.MenuId , sourceTable.ParentId , inserted.MenuID INTO
#Holder (OriginalMenuId , [OriginalParentId] , NewMenuSurrogateKey );
Select 'Before the NewParentIdSurrogateKey is Updated Values' as Lab1 , * from #Holder
Update holderAsParent Set NewParentIdSurrogateKey = holderAsChild.NewMenuSurrogateKey
/* You can comment out the previous update and uncomment the next select statement to see what the update is trying to do */
/* Select 'Here1' as Lab1 , holderAsChild.NewMenuSurrogateKey, '----' as Sep1, holderAsChild.* , '----' as Sep2 , holderAsParent.* */
from
#Holder holderAsChild
join #Holder holderAsParent on holderAsChild.OriginalMenuId = holderAsParent.OriginalParentId
Select 'ShouldHaveAllTheMappingValuesInTheHolderNow' as Lab1 , * from #Holder
Update dbo.Menu Set [ParentId] = holder.NewParentIdSurrogateKey
from
dbo.Menu men join #Holder holder on men.MenuId = holder.NewMenuSurrogateKey
where holder.NewParentIdSurrogateKey iS NOT NULL
Select 'Final Results' as Lab1 , * from dbo.Menu
IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
begin
drop table #Holder
end
/* Sanity Check */
Select COALESCE(parent.MenuName + ' -- ', '') + child.MenuName as ParentThenChildMenuName, child.VersionNumber
from
[dbo].[Menu] child
left join
[dbo].[Menu] parent
on child.ParentId = parent.MenuId
where child.VersionNumber = 1
order by parent.MenuName , child.MenuName
Select COALESCE(parent.MenuName + ' -- ', '') + child.MenuName as ParentThenChildMenuName, child.VersionNumber
from
[dbo].[Menu] child
left join
[dbo].[Menu] parent
on child.ParentId = parent.MenuId
where child.VersionNumber = 2
order by parent.MenuName , child.MenuName
Below is a reference. This was the little hint to led to using MERGE in the "from_table_name" for this particular situation.
http://msdn.microsoft.com/en-us/library/ms177564.aspx
“from_table_name”
Is a column prefix that specifies a table included in the FROM clause of a DELETE, UPDATE, or MERGE statement that is used to specify the rows to update or delete.

Resources