I am working with SQL sever table and at technical point I am stuck.
Below I am attaching a screen-shot of the table query and result also the required logic.
There are two portions of query, one is without any condition and second is with condition that select "qty" when parent_id is NULL else print 0,
I want to print the "qty" of sub-item when its qty differs from its parent's "qty"
Here is the script:
GO
CREATE TABLE [dbo].[#Temp_order](
[order_id] [int] IDENTITY(1,1) NOT NULL,
[orderdate] [datetime] NULL
) ON [PRIMARY]
GO
GO
CREATE TABLE [dbo].[#Temp_order_list](
[order_list_id] [int] IDENTITY(1,1) NOT NULL,
[order_id] [int] NOT NULL,
[qty] [int] NOT NULL,
[price] [money] NOT NULL,
[type] [int] NOT NULL,
[parent_id] [int] NULL,
CONSTRAINT [PK_Temp_order_list] PRIMARY KEY CLUSTERED
(
[order_list_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 INTO #Temp_order
( orderdate )
VALUES ( '2015-01-16 05:08:53' -- orderdate - datetime
)
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
1, -- qty - int
10, -- price - money
2, -- type - int
NULL -- parent_id - int
)
DECLARE #ParentID AS INTEGER
SELECT #ParentID = MAX(order_list_id) FROM #Temp_order_list
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
1, -- qty - int
12, -- price - money
3, -- type - int
#ParentID -- parent_id - int
)
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
4, -- qty - int
13, -- price - money
3, -- type - int
#ParentID -- parent_id - int
)
SELECT * FROM #Temp_order_list WHERE order_id = 1
SELECT #Temp_order.order_id ,#Temp_order_list.order_list_id,#Temp_order_list.price,#Temp_order_list.type,
CASE WHEN #Temp_order_list.parent_id IS NOT NULL THEN 0
ELSE
ISNULL(#Temp_order_list.qty ,'') END AS quantity
FROM #Temp_order
INNER JOIN #Temp_order_list ON #Temp_order.order_id = #Temp_order_list.order_id
WHERE #Temp_order.order_id = 1
DROP TABLE #Temp_order
DROP TABLE #Temp_order_list
Any better solution?
Looking at your last comment, I can suggest to add self join and check that condition :
SELECT ordr.order_id,
list.order_list_id,
list.price,
list.type,
CASE
WHEN parentlist.order_list_id IS NOT NULL THEN list.qty
WHEN list.parent_id IS NOT NULL THEN 0
ELSE ISNULL(list.qty, '')
END AS quantity
FROM #Temp_order ordr
INNER JOIN #Temp_order_list list
ON ordr.order_id = list.order_id
LEFT JOIN #Temp_order_list parentlist
ON parentlist.order_list_id = list.parent_id
AND list.qty > parentlist.qty
AND list.type = 3
WHERE ordr.order_id = 1
Related
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 am trying to insert data from one database table to another database table. This work is performed very well but need bypass that duplicate data cannot be inserted. Here is my query below. How can I check duplicate record?
;WITH ABC AS (
SELECT
5 AS DeviceID
, nUserID AS CardNo
, CONVERT(DATE, dbo.fn_ConvertToDateTime(nDateTime)) AS InOutDate
, CONVERT(VARCHAR(8) ,CONVERT(TIME,dbo.fn_ConvertToDateTime(nDateTime))) AS InOutTime
FROM [BioStar].[dbo].[TB_EVENT_LOG]
)
SELECT * INTO #tempAtten FROM ABC
INSERT [HR].[dbo].[HR_DeviceInOut](DeviceID, CardNo, InOutDate, InOutTime, ShiftprofileID, ExecutedBy)
SELECT DeviceID, CardNo, InOutDate, InOutTime, NULL, NULL
FROM #tempAtten
WHERE #tempAtten.InOutDate = CONVERT(DATE, GETDATE()) AND #tempAtten.CardNo <> 0
DROP TABLE #tempAtten
--HR_DeviceInOut
CREATE TABLE [dbo].[HR_DeviceInOut](
[id] [bigint] IDENTITY(100000000000001,1) NOT NULL,
[DeviceID] [nvarchar](20) NULL,
[CardNo] [nvarchar](20) NOT NULL,
[InOutDate] [date] NOT NULL,
[InOutTime] [nvarchar](10) NOT NULL,
[ShiftprofileID] [tinyint] NULL,
[ExecutedBy] [int] NULL,
CONSTRAINT [PK_HR_AttenHistory] 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
--Function
ALTER FUNCTION [dbo].[fn_ConvertToDateTime] (#Datetime BIGINT)
RETURNS DATETIME
AS
BEGIN
DECLARE #LocalTimeOffset BIGINT
,#AdjustedLocalDatetime BIGINT;
SET #LocalTimeOffset = DATEDIFF(second,GETDATE(),GETUTCDATE())
SET #AdjustedLocalDatetime = #Datetime - #LocalTimeOffset
RETURN (SELECT DATEADD(second,#AdjustedLocalDatetime, CAST('1970-01-01 00:00:00' AS datetime)))
END;
Assuming I'm understanding correctly, here's one option using not exists:
INSERT [HR].[dbo].[HR_DeviceInOut] (DeviceID, CardNo, InOutDate,
InOutTime, ShiftprofileID, ExecutedBy)
SELECT DeviceID, CardNo, InOutDate, InOutTime, NULL, NULL
FROM #tempAtten t
WHERE t.InOutDate = CONVERT(DATE, GETDATE()) AND
t.CardNo <> 0 AND
NOT EXISTS (
SELECT 1
FROM [HR].[dbo].[HR_DeviceInOut] d
WHERE t.DeviceID = d.DeviceId AND
t.CardNo = d.CardNo AND
t.InOutDate = d.InOutDate AND
t.InOutTime = d.InOutTime
)
Consider adding a unique_index to the those fields that cannot be duplicated.
Which column set make record unique as i see some column are hard coded
ie 5 AS DeviceID ...
Create unique key for rest of the column in temp table and destinationtabel.to avoid duplicate .
I have simple table which puzzles me:
CREATE TABLE [dbo].[T3]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[S_Id] [int] NULL,
[P_Id] [int] NULL,
[level] [int] NULL,
[Path] [nvarchar](255) NULL
) ON [PRIMARY]
In the table is data
id S_Id P_Id level Path
------------------------------------
1 218252 218231 1 218231
2 218271 218252 1 218252
3 218271 218252 2 218231-218252
EDIT:
I try to get the
ID, S_ID, P_ID, level, Path
on maximum length of column Path.
It should return id 3.
If I try to get max len from path like this:
select
b.id, a.p_id, a.s_id,
max(len(a.path)) as Path,
a.path
from
t3 a, t3 b
where
b.id = a.id
group by
a.p_id , a.s_id, b.id , a.path
order by
1
I get all the data, not just row with id 3, why ?
If you only want the max path record... Correct me if I'm wrong.
;WITH tmp AS (select TOP 1 id from #TaskTask3 ORDER BY LEN(path) DESC)
select t.*
from #TaskTask3 t
inner join tmp on tmp.id = t.id
Updates
;WITH tmp AS (select id, row_number() over (partition by S_Id, P_Id order by len(path) DESC) as rn from #TaskTask3)
select t.*
from #TaskTask3 t
inner join tmp on tmp.id = t.id
WHERE tmp.rn = 1
I tried to keep it simple....There are other methods (mentioned already) but I think you need to start slow... :)
declare #maxLen int
select #maxLen = max(len(path))
from t3
select * from t3
where len (path) = #maxLen
To put weePee's answer in a simple way,you can use the following query:
select id,s_id,p_id,level from t3 where len(path)= (select max(len(path)) from t3)
This is what I used to create and insert into table t3:
CREATE TABLE [dbo].[T3]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[S_Id] [int] NULL,
[P_Id] [int] NULL,
[level] [int] NULL,
[Path] [nvarchar](255) NULL
) ON [PRIMARY]
insert into t3 (s_id,p_id,level,path) values (218252,218231,1,'218231'),(218271,218252,1,'218252'),(218271,218252,2,'218231-218252')
i want to know how i can rewrite this SQL into a single select using joins. i have a long drawn out way as seen below to basically get the min date of a "project inception milestone" and max date for a "production go-live" milestone.
some background is the sql is for a project management application that tracks projects milestones against a release baseline set of milestones. I need to have a proc that takes a CSV list of projectIDs and have it select the min startDate for the project inception milestone (StatusCode.cid =37) and the max production go-live milestone(StatusCode.cid =77)
here is my dummy SQL i have working now:
CREATE PROC rpt_rainbow
#ProjectIDs NVARCHAR(1000)
AS
DECLARE #MinBRSProjectStartDate DATETIME
DECLARE #MinBRSReleaseStartDate DATETIME
DECLARE #MaxProdProjectEndDate DATETIME
DECLARE #MaxProdReleaseEndDate DATETIME
SELECT #MinBRSProjectStartDate = MIN (pm.startDate)
FROM StatusCode sc
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID AND pm.ProjectID IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
WHERE sc.cid =37
SELECT #MinBRSReleaseStartDate = MIN(rel.startDate)
FROM Project p
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (37)
WHERE ProjectId IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
SELECT #MaxProdProjectEndDate = MAX (pm.endDate)
FROM StatusCode sc
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID AND pm.ProjectID IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
WHERE sc.cid =77
SELECT #MaxProdReleaseEndDate = MAX(rel.endDate)
FROM Project p
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (77)
WHERE ProjectId IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
select isnull(#MinBRSProjectStartDate, #MinBRSReleaseStartDate) as MinBRS_StartDate,
isnull(#MaxProdProjectEndDate, #MaxProdReleaseEndDate) as MaxProd_EndDate
here is my split function:
CREATE FUNCTION dbo.Split
( #Delimiter varchar(5),
#List varchar(8000)
)
RETURNS #TableOfValues table
( RowID smallint IDENTITY(1,1),
[Value] varchar(50)
)
AS
BEGIN
DECLARE #LenString int
WHILE len( #List ) > 0
BEGIN
SELECT #LenString =
(CASE charindex( #Delimiter, #List )
WHEN 0 THEN len( #List )
ELSE ( charindex( #Delimiter, #List ) -1 )
END
)
INSERT INTO #TableOfValues
SELECT substring( #List, 1, #LenString )
SELECT #List =
(CASE ( len( #List ) - #LenString )
WHEN 0 THEN ''
ELSE right( #List, len( #List ) - #LenString - 1 )
END
)
END
RETURN
END
and here are the definitions for the tables involved:
CREATE TABLE [dbo].[ProjectMilestone](
[ProjectMilestoneId] [int] NOT NULL,
[ProjectId] [int] NOT NULL,
[MilestoneCID] [int] NOT NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
[RAGStatusCID] [int] NOT NULL,
[CompletionStatusCID] [int] NOT NULL,
[StatusText] [nvarchar](max) NOT NULL,
[ReportingPriority] [int] NULL,
[Owner] [nvarchar](50) NOT NULL,
[Added] [datetime] NOT NULL,
[LastUpdate] [datetime] NOT NULL,
[UpdateBy] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_ProjectMilestone] PRIMARY KEY CLUSTERED
(
[ProjectMilestoneId] 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
ALTER TABLE [dbo].[ProjectMilestone] WITH CHECK ADD CONSTRAINT [FK_ProjectMilestone_Project] FOREIGN KEY([ProjectId])
REFERENCES [dbo].[Project] ([ProjectId])
GO
ALTER TABLE [dbo].[ProjectMilestone] CHECK CONSTRAINT [FK_ProjectMilestone_Project]
-----------------------------------------------------------------------------------------------
CREATE TABLE [dbo].[Project](
[ProjectId] [int] NOT NULL,
[ProjectName] [nvarchar](255) NOT NULL,
[ProjectRegistration] [nvarchar](50) NOT NULL,
[CaseManagerBenId] [nvarchar](50) NOT NULL,
[ClarityId] [nvarchar](50) NOT NULL,
[ParentProjectId] [int] NULL,
[ReleaseId] [int] NOT NULL,
[CompletionStatusCID] [int] NOT NULL,
[ProjectTypeCID] [int] NOT NULL,
[Budget] [money] NOT NULL,
[BusinessObjective] [nvarchar](max) NOT NULL,
[Benefit] [nvarchar](max) NOT NULL,
[Added] [datetime] NOT NULL,
[LastUpdate] [datetime] NOT NULL,
[UpdateBy] [nvarchar](50) NOT NULL,
[StakeholderList] [nvarchar](1000) NULL,
CONSTRAINT [PK_Project] PRIMARY KEY CLUSTERED
(
[ProjectId] 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
ALTER TABLE [dbo].[Project] WITH CHECK ADD CONSTRAINT [FK_Project_Project] FOREIGN KEY([ParentProjectId])
REFERENCES [dbo].[Project] ([ProjectId])
GO
ALTER TABLE [dbo].[Project] CHECK CONSTRAINT [FK_Project_Project]
GO
ALTER TABLE [dbo].[Project] WITH CHECK ADD CONSTRAINT [FK_Project_Release] FOREIGN KEY([ReleaseId])
REFERENCES [dbo].[Release] ([ReleaseId])
GO
ALTER TABLE [dbo].[Project] CHECK CONSTRAINT [FK_Project_Release]
--------------------------------------------------------------------------------------------
CREATE TABLE [dbo].[StatusCode](
[CID] [int] NOT NULL,
[CodeName] [nvarchar](50) NOT NULL,
[Description] [nvarchar](max) NOT NULL,
[SCID] [int] NOT NULL,
[ReportingPriority] [int] NULL,
CONSTRAINT [PK_StatusCode] PRIMARY KEY CLUSTERED
(
[CID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
--------------------------------------------------------------------------------------------
CREATE TABLE [dbo].[ReleaseSchedule](
[ReleaseScheduleID] [int] NOT NULL,
[ReleaseID] [int] NOT NULL,
[MilestoneCID] [int] NOT NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL,
[Added] [datetime] NOT NULL,
[LastUpdate] [datetime] NOT NULL,
[UpdateBy] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_ReleaseSchedule] PRIMARY KEY CLUSTERED
(
[ReleaseScheduleID] 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
ALTER TABLE [dbo].[ReleaseSchedule] WITH CHECK ADD CONSTRAINT [FK_ReleaseSchedule_Release] FOREIGN KEY([ReleaseID])
REFERENCES [dbo].[Release] ([ReleaseId])
GO
ALTER TABLE [dbo].[ReleaseSchedule] CHECK CONSTRAINT [FK_ReleaseSchedule_Release]
There are two things of note, the first is that you could reduce the 4 queries to 2
SELECT
#MinBRSProjectStartDate = MIN (CASE WHEN sc.cid=37 then pm.startDate END),
#MaxProdProjectEndDate = MAX (CASE WHEN sc.cid=77 then pm.endDate END)
FROM StatusCode sc
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID
AND pm.ProjectID IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
WHERE sc.cid in (37,77)
SELECT
#MinBRSReleaseStartDate = MIN(CASE WHEN rel.milestonecid=37 then rel.startDate end),
#MaxProdReleaseEndDate = MAX(CASE WHEN rel.milestonecid=77 then rel.endDate end)
FROM Project p
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (37,77)
WHERE ProjectId IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
There is really no way to join between these two sets, so there is no point trying. But you could CROSS JOIN the two single-row results to get all 4 columns in a single select:
SELECT ISNULL(A,C) as MinBRS_StartDate, ISNULL(B,D) AS MaxProd_EndDate
FROM
(
SELECT
MIN (CASE WHEN sc.cid=37 then pm.startDate END) A,
MAX (CASE WHEN sc.cid=77 then pm.endDate END) B
FROM StatusCode sc
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID
AND pm.ProjectID IN (SELECT value FROM fn_Split(#ProjectIDs, ','))
WHERE sc.cid in (37,77)
) X,
(
SELECT
MIN(CASE WHEN rel.milestonecid=37 then rel.startDate end) C,
MAX(CASE WHEN rel.milestonecid=77 then rel.endDate end) D
FROM Project p
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID AND rel.milestonecid IN (37,77)
WHERE ProjectId IN (SELECT value FROM fn_Split(#ProjectIDs, ','))) Y
But since you are using ISNULL across the 2 pairs, it may be better to keep the 4 targeted index-able selects and to just subquery them. Since you are using the SPLIT values 4 times, it makes sense to cache it in a temp table. The ISNULL should be smart enough not to need to evaluate the 2nd select once the first returns a value.
declare #ids table (id int)
insert #ids SELECT distinct value FROM fn_Split(',', #ProjectIDs) V
SELECT
ISNULL(
(SELECT MIN (pm.startDate)
FROM StatusCode sc
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID
INNER JOIN #ids I ON pm.ProjectID = I.ID
WHERE sc.cid =37),
(SELECT MIN(rel.startDate)
FROM Project p
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID
INNER JOIN #ids I ON p.ProjectID = I.ID
WHERE rel.milestonecid IN (37))) AS MinBRS_StartDate,
ISNULL(
(SELECT MAX (pm.endDate)
FROM StatusCode sc
INNER JOIN ProjectMilestone pm ON sc.CID = pm.MilestoneCID
INNER JOIN #ids I ON pm.ProjectID = I.ID
WHERE sc.cid =77),
(SELECT MAX(rel.endDate)
FROM Project p
INNER JOIN ReleaseSchedule rel ON rel.ReleaseID = p.ReleaseID
INNER JOIN #ids I ON p.ProjectID = I.ID
WHERE rel.milestonecid IN (77))) AS MaxProd_EndDate
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