I want to calculate SUM of all children with CTE here is DDL/DML. 0 values are which I don't know and to be calculated through aggregation
CREATE TABLE [dbo].[Product]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Hierarchy] [VARCHAR](100) NOT NULL,
[ParentID] [INT] NULL,
[SalesAmount] [INT] NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Product] ON
GO
INSERT [dbo].[Product] ([ID], [Hierarchy], [ParentID], [SalesAmount])
VALUES (1, N'root', NULL, 0),
(2, N'T1', 1, 0),
(3, N'T2', 1, 0),
(4, N'C1', 2, 0),
(5, N'C2', 3, 0),
(6, N'C3', 2, 0),
(7, N'P1', 4, 1000),
(8, N'P2', 5, 2000),
(9, N'P3', 6, 3000)
I tried below query and it gives me following output,
WITH CT AS
(
SELECT
ID, Hierarchy, ParentID, 0 AS Level,
CAST ([Hierarchy] AS VARCHAR (MAX)) AS [Linkeage]
FROM
dbo.Product
WHERE
ParentID IS NULL
UNION ALL
SELECT
pc.ID, pc.Hierarchy, pc.ParentID, p1.Level + 1,
p1.Linkeage + ' -> ' + CAST ([pc].[Hierarchy] AS VARCHAR (MAX))
FROM
dbo.Product AS pc
JOIN
CT AS p1 ON p1.ID = pc.ParentID
),
Aggr AS
(
SELECT
TC.ParentID,
SUM(T.SalesAmount) AS sum_TotalAmt
FROM
CT TC
INNER JOIN
Product AS T ON TC.ID = T.ID
GROUP BY
TC.ParentID
)
SELECT
ID, Hierarchy, T.ParentID, Level, Linkeage, A.sum_TotalAmt
FROM
CT AS T
LEFT JOIN
Aggr AS A ON ISNULL(T.Id, T.ParentID) = A.ParentID
I need existing output + underlined rows as well.
I figured out by my-self by in different approach, i wanted to get aggregates of multiple group by values,
CREATE TABLE [dbo].[Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductType] [varchar](100) NOT NULL,
[ProductCategory] [varchar](100) NOT NULL,
[ProductName] [varchar](100) NOT NULL,
[SalesAmount] [decimal]
) ON [PRIMARY]
So i can simply get output with below
select [ProductType], [ProductCategory], SUM( [SalesAmount] ) as TotalSales
from Product
GROUP BY ROLLUP (ProductType,ProductCategory)
Related
I have three tables, table 1, table 2 and table 3. Table 1 records all the existing records, and table 2 records the delta (new updates) to be applied to table 1.
Table 3 is the resultant table.
Table 1 and 3 structure: ID is the primary key
ID, date, location, age, count
Table 2 structure: ID is the primary key
ID, date, location, age, count, ChangeType
Table 2 records new update values only for fields that changed in table 1.
For example:
Table 1
1, 03/03/2017, A, 11, 1
2, 01/03/2017, B, 39, 1
3, 01/01/2017, D, 1, 1
Table 2
2, 03/03/2017,NULL, NULL,2, Update
1, NULL, CC, NULL, NULL, Update
Therefore table 3 should be
1, 03/03/2017, CC, 11, 1
2, 03/03/2017, B, 39, 2
3, 01/01/2017, D, 1, 1
Any suggestions would be appreciated.
GO
/****** Object: Table [dbo].[Table_1] Script Date: 03/03/2017 10:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_1](
[ID] [int] NOT NULL,
[date] [date] NULL,
[location] [nvarchar](50) NULL,
[age] [int] NULL,
[count] [int] NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Table_2] Script Date: 03/03/2017 10:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_2](
[ID] [int] NOT NULL,
[date] [date] NULL,
[location] [nvarchar](50) NULL,
[age] [int] NULL,
[count] [int] NULL,
[ChangeTyppe] [nvarchar](10) NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Table_3] Script Date: 03/03/2017 10:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_3](
[ID] [int] NOT NULL,
[date] [date] NULL,
[location] [nvarchar](50) NULL,
[age] [int] NULL,
[count] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table_1] ([ID], [date], [location], [age], [count]) VALUES (1, CAST(0x863C0B00 AS Date), N'A', 11, 1)
GO
INSERT [dbo].[Table_1] ([ID], [date], [location], [age], [count]) VALUES (2, CAST(0x843C0B00 AS Date), N'B', 39, 1)
GO
INSERT [dbo].[Table_1] ([ID], [date], [location], [age], [count]) VALUES (3, CAST(0x493C0B00 AS Date), N'D', 1, 1)
GO
INSERT [dbo].[Table_2] ([ID], [date], [location], [age], [count], [ChangeTyppe]) VALUES (2, CAST(0x863C0B00 AS Date), NULL, NULL, 2, N'Update')
GO
INSERT [dbo].[Table_2] ([ID], [date], [location], [age], [count], [ChangeTyppe]) VALUES (1, NULL, N'CC', NULL, NULL, N'Update')
GO
If all you need is a one time thing, then this should work.
Left Join the two tables on the primary key and take the value from T2 if it is not null. Take the value from T1 if the value from 2 was null.
Coalesce will return the first value which is not null.
The values from T2 will be null if the row did not exist in T2 or if the value in T2 was null - per ID.
INSERT dbo.Table_3
( ID, date, location, age, count )
SELECT t1.ID ,
[date] = COALESCE(t2.date, t1.date) ,
[location] = COALESCE(t2.location, t1.location) ,
[age] = COALESCE(t2.age, t1.age) ,
[count] = COALESCE(t2.count, t1.count)
FROM dbo.Table_1 t1
LEFT OUTER JOIN dbo.Table_2 t2 ON t2.ID = t1.ID
CREATE TABLE [dbo].[Test]
( [GID] INT
, [ID] INT
, [Val] VARCHAR(10)
, [ParentId] INT
, CONSTRAINT [PK_Test] PRIMARY KEY ( [GID], [ID] )
, CONSTRAINT [FK_Test_ParentId] FOREIGN KEY ( [GID], [ParentId] ) REFERENCES [dbo].[Test] ( [GID], [id] ) );
INSERT INTO [dbo].[Test] ([GID], [ID], [Val], [ParentId])
SELECT 1, 1,'One',NULL
UNION
SELECT 1, 2,'Two',NULL
UNION
SELECT 1, 3,'Three',1
UNION
SELECT 1, 4,'Four',1
UNION
SELECT 2, 1,'One',NULL
UNION
SELECT 2, 2,'Two',1;
SELECT *
FROM [dbo].[Test];
/* Test Cases */
--UPDATE [dbo].[Test]
--SET [ParentId] = 2
--WHERE [GID] = 1 AND [ID] = 1; -- Should FAIL because this record is already marked as a Parent of another record(s) (i.e. [GID] = 1 AND [ID] IN (3, 4)
--INSERT INTO [dbo].[Test] ( [GID], [ID], [Val], [ParentId] )
--SELECT 1, 5, 'Five', 4; -- Should FAIL because [GID] = 1 AND [ID] = 4 already has a non-null [ParentId].
DROP TABLE [dbo].[Test];
Goal:
To create a check constraint (scalar function with BIT return where 1 = valid, 0 = invalid?) that prevents the mapped ParentID record from having a NOT-NULL ParentId or preventing an INSERT of a record with a ParentId that already has a NOT-NULL ParentID assigned to it.
I tried to play around with LEFT Joins/NULL check logic but not really getting what I'm looking for.
I have an Employee table and how it works is, when a new employee is added, the column [DOR] will be null and [Status] will be 1. When the employee is being relieved from the company, the [DOR] column value will be the date which he/she left the company and [Status] is set to 0.
I need to fetch the details of all the employees who were available in a given date. The employees with Status as 1 and those who are not yet relieved till that date have to be fetched.
But I am not able to do the same as when equating with DOR, its null value and not returning any of the rows.
If I give the input as 2015-02-10, it should fetch the two records and when I give 2015-02-15, it should fetch only first record.
CREATE TABLE [Employee]
(
[EmployeeId] [int] IDENTITY(1000,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[RoleId] [int] NOT NULL,
[Email] [varchar](50) NULL,
[Contact] [varchar](50) NULL,
[DOJ] [date] NOT NULL,
[DOR] [date] NULL,
[Status] [bit] NOT NULL,
[Salary] [decimal](18, 2) NULL
)
INSERT [dbo].[Employee] ([EmployeeId], [Name], [RoleId], [Email], [Contact], [DOJ], [DOR], [Status], [Salary])
VALUES (1001, N'Employee 1', 3, N'', N'', CAST(0x8D390B00 AS Date), NULL, 1, CAST(6000.00 AS Decimal(18, 2)))
INSERT [dbo].[Employee] ([EmployeeId], [Name], [RoleId], [Email], [Contact], [DOJ], [DOR], [Status], [Salary])
VALUES (1002, N'Employee 2', 7, N'', N'', CAST(0x8D390B00 AS Date), CAST(0x9A390B00 AS Date), 0, CAST(4000.00 AS Decimal(18, 2)))
You need to use IS NULL operator instead of = NULL in your condition, like this:
SELECT *
FROM Employee
WHERE DOJ <= '2015-02-15'
AND (DOR IS NULL OR DOR > '2015-02-15')
Something like this?
select
EmployeeId,
Name
from
Employee
where
DOJ <= #searchDate and
(DOR is null or DOR > #searchDate)
Try this:
SELECT * FROM Employee
WHERE #dateOfSearch BETWEEN DOJ and COALESCE(DOR, '2099-12-31')
What this query does, is it checks if the search date is between start date and end date. If end date is null then COALESCE function is used to take the very high value date.
Another variation of the previous answers :-)
SELECT * FROM Employee
WHERE #dateOfSearch BETWEEN DOJ and COALESCE(DOR, #dateOfSearch)
I have created a dummy scenario that reflect many of the queries I have to write to check that some data we are importing is correct.
The example would be when you have 3 tables
Store
Customer
CustomerOrder
A Customer can belong to many stores but can only 1 OrderOnsale can be bought x customer x store.
Cannot seem to get it right. Below is tables and noddy data + my attempt.
IF object_id(N'Store', 'U') IS NOT NULL
DROP TABLE Store
GO
CREATE TABLE [dbo].[Store]
(
[Id] [bigint] NOT NULL,
[StoreName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Store] PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY]
GO
IF object_id(N'Customer', 'U') IS NOT NULL
DROP TABLE Customer
GO
CREATE TABLE [dbo].[Customer]
(
[CustomerId] [bigint] NOT NULL,
[StoreId] [bigint] NOT NULL,
[Name] [varchar](50) NOT NULL,
[Surname] [varchar](50) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ([CustomerId] ASC)
) ON [PRIMARY]
GO
IF object_id(N'CustomerOrder', 'U') IS NOT NULL
DROP TABLE CustomerOrder
GO
CREATE TABLE [dbo].[CustomerOrder]
(
[OrderId] [bigint] NOT NULL,
[CustomerId] [bigint] NOT NULL,
[OrderName] [varchar](50) NOT NULL,
[OnSale] [bit] NOT NULL,
CONSTRAINT [PK_CustomerOrder] PRIMARY KEY CLUSTERED([OrderId] ASC)
) ON [PRIMARY]
GO
begin tran
INSERT INTO [dbo].[Store]([Id], [StoreName])
SELECT 1, N'Harrods' UNION ALL
SELECT 2, N'John Lewis'
INSERT INTO [dbo].[Customer]([CustomerId], [StoreId], [Name], [Surname])
SELECT 1, 1, N'John', N'Smith' UNION ALL
SELECT 2, 2, N'Joe', N'Blogg'
INSERT INTO [dbo].[CustomerOrder]([OrderId], [CustomerId], [OrderName], [OnSale])
SELECT 1, 1, N'Toys', 1 UNION ALL
SELECT 2, 1, N'Laptop', 1 UNION ALL
SELECT 3, 2, N'Toys', 0
commit
My incomplete attempt:
SELECT
HasCustomerBoughtMoreThanO1ItemOnSale =
CASE WHEN Count(T2.TotalBoughtOnSale) > 1 THEN 1 ELSE 0 END
FROM
CustomerOrder co1
INNER JOIN
customer c1 ON co1.CustomerId = c1.CustomerId
INNER JOIN
STORE S01 ON C1.StoreId = S01.Id
JOIN
(SELECT
CO2.CustomerId, S2.Id AS StoreId,
Count(CO2.OnSale) TotalBoughtOnSale
FROM
CustomerOrder CO2
INNER JOIN
customer c2 ON c2.CustomerId = CO2.CustomerId
INNER JOIN
STORE S2 ON C2.StoreId = S2.Id
WHERE
CO2.OnSale = 1
GROUP BY
CO2.CustomerId, S2.Id) AS t2 ON c1.CustomerId = T2.CustomerId
AND S01.Id = t2.StoreId
If what your after is if a single customer has bought more then one OnSale item then this query will do the trick.
SELECT
CO.CustomerId, C.StoreId
FROM CustomerOrder CO
INNER JOIN Customer C ON CO.CustomerId = C.CustomerId
WHERE OnSale = 1
GROUP BY CO.CustomerId, C.StoreId
HAVING COUNT(*) > 1
I should add that in this its given that a Customer can only shop in a single Store due to StoreId is a column in the Customer table.
I have sales table which consists, ItemSize, GroupName, Quantity, ProductID, etc...
Now I want to display sales according to following format
GroupName ItemSize Quantity ItemSize Quantity
means
BEER 350ml 500 650ml 1000
How I can achieve this in SQL SERVER 2005 EXPRESS (T-SQL)? Thanks
UPDATED:
its my sales table structure
CREATE TABLE [dbo].[SalesLog](
[SalesID] [int] IDENTITY(1,1) NOT NULL,
[MemoNo] [int] NULL,
[ProductCode] [int] NULL,
[Quantity] [int] NULL,
[Price] [int] NULL,
[ProductGroup] [int] NULL,
CONSTRAINT [PK_SalesLog] PRIMARY KEY CLUSTERED
(
[SalesID] ASC
) WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
its my Product table structure
CREATE TABLE [dbo].[Products](
[ProductId] [int] IDENTITY(1,1) NOT NULL,
[pName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[pSize] [int] NULL,
[pPrice] [int] NULL,
[pPackQty] [int] NULL,
[pGroup] [int] NULL,
[pCode] [int] NULL,
[pStock] [int] NULL,
[pYrStock] [int] NULL,
[pClearStock] [int] NULL,
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
(
[ProductId] ASC
) WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
You could aggregate the data using SUM and CASE statements.
Using your table definitions (and some very minimal made up data), here is an example of how you could do it:
--** Create test tables
DECLARE #SalesLog TABLE (
SalesID int IDENTITY(1,1) NOT NULL,
MemoNo int NULL,
ProductCode int NULL,
Quantity int NULL,
Price int NULL,
ProductGroup int NULL)
DECLARE #Products TABLE(
ProductId int IDENTITY(1,1) NOT NULL,
pName nvarchar(50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
pSize int NULL,
pPrice int NULL,
pPackQty int NULL,
pGroup int NULL,
pCode int NULL,
pStock int NULL,
pYrStock int NULL,
pClearStock int NULL)
--** Setup test data
INSERT INTO #SalesLog ( MemoNo, ProductCode, Quantity, Price, ProductGroup)
SELECT 0, 1, 500, 0, 1 UNION
SELECT 0, 2, 700, 0, 1 UNION
SELECT 0, 2, 333, 0, 1 UNION
SELECT 0, 3, 200, 0, 2 UNION
SELECT 0, 4, 125, 0, 2 ;
INSERT INTO #Products (pName, pSize, pPrice, pPackQty, pGroup, pCode, pStock, pYrStock, pClearStock)
SELECT 'Beer', 350, 1 , 1, 1, 1, 0, 0, 0 UNION
SELECT 'Beer', 650, 1 , 1, 1, 2, 0, 0, 0 UNION
SELECT 'Beer', 1000, 1 , 1, 1, 3, 0, 0, 0 UNION
SELECT 'Wine', 750, 1 , 1, 2, 4, 0, 0, 0 UNION
SELECT 'Wine', 1000, 1 , 1, 2, 5, 0, 0, 0 ;
--** Example query
SELECT t.pName AS 'Product'
, MAX(CASE WHEN t.Col = 1 THEN t.pSize END) AS 'Item Size'
, ISNULL(SUM(CASE WHEN t.Col = 1 THEN t.Quantity END),0) AS 'Quantity'
, MAX(CASE WHEN t.Col = 2 THEN t.pSize END) AS 'Item Size'
, ISNULL(SUM(CASE WHEN t.Col = 2 THEN t.Quantity END),0) AS 'Quantity'
, MAX(CASE WHEN t.Col = 3 THEN t.pSize END) AS 'Item Size'
, ISNULL(SUM(CASE WHEN t.Col = 3 THEN t.Quantity END),0) AS 'Quantity'
FROM (
SELECT pName
, pCode
, pGroup
, pSize
, sl.Quantity
, DENSE_RANK() OVER(PARTITION BY p.pGroup ORDER BY p.pSize) AS Col
FROM #Products AS p
LEFT JOIN #SalesLog AS sl
ON p.pGroup = sl.ProductGroup
AND p.pCode = sl.ProductCode
) AS t
GROUP BY t.pGroup
, t.pName
;
The query uses the DENSE_RANK function to group items of a size together and to order them in assending order of size and this is used to work out which column the data should be written to.
Although there is a PIVOT operator in SQL Server 2005 and above, it isn't very helpful when you have different column heading types (item size and quantity in this case).
You will have to decide on the maximum number of product sizes that you want to report on as this is hard coded into the query. So if the maximum number of product sizes is 3 then you code the query as shown above. If, however, one of your products has 4 different sizes, then you are going to add an additional Item Size and Quantity pair of columns for t.Col = 4 and so on.
I hope this helps.
It looks like you are trying to do a PIVOT table, where the different item sizes are represented as different columns rather than rows. Take a look at http://msdn.microsoft.com/en-us/library/ms177410.aspx