SQL Server Count items available - sql

I am building a pretty simple inventory items database that will allow me to check out items between dates. I will need to return a single row that will tell me the available, reserved, and total inventory of this item. I cannot seem to get this correct.
BEGIN TRAN
DECLARE #startDate AS DATE
DECLARE #endDate AS DATE
DECLARE #partID AS INT
SET #startDate = '4/15/2015'
SET #endDate = '4/25/2015'
SET #partID = 248
SELECT COUNT(ii.[PartId] WHERE ii.[PartStatus] = 1 ) AS [Available],
COUNT(ii.[PartId] WHERE ii.[PartStatus] = 2 ) AS [Reserverd],
COUNT(ii.[PartId] WHERE ii.[PartStatus] <> 4 ) AS [TotalInventory],
FROM ShipListInventory.dbo.InventoryItems AS ii
LEFT JOIN ShipListInventory.dbo.InventoryItemCalendars AS iic
ON iic.[ItemId] = ii.[Id]
WHERE iic.[StartDate] NOT BETWEEN #startDate AND #endDate
AND iic.[InboundDate] NOT BETWEEN #startDate AND #endDate
AND ii.[PartId] = 248
COMMIT TRAN
EDIT: I am only returning rows from InventoryItemCalendarsI want to return items from InventoryItems
CREATE TABLE [dbo].[InventoryItems](
[Id] [INT] IDENTITY(1,1) NOT NULL,
[PartSatuts] [INT] NOT NULL,
[PartId] [INT] NOT NULL,
[Barcode] [NVARCHAR](MAX) NULL,
[PicturePath] [NVARCHAR](255) NULL,
[Notes] [NVARCHAR](1000) NULL,
CONSTRAINT [PK_dbo.InventoryItems] 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
ALTER TABLE [dbo].[InventoryItems] WITH CHECK ADD CONSTRAINT [FK_dbo.InventoryItems_dbo.Parts_PartId] FOREIGN KEY([PartId])
REFERENCES [dbo].[Parts] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[InventoryItems] CHECK CONSTRAINT [FK_dbo.InventoryItems_dbo.Parts_PartId]
GO
CREATE TABLE [dbo].[InventoryItemCalendars](
[Id] [INT] IDENTITY(1,1) NOT NULL,
[StartDate] [DATETIME] NOT NULL,
[InboundDate] [DATETIME] NOT NULL,
[ProjectNumber] [INT] NOT NULL,
[ItemId] [INT] NOT NULL,
[Project_Id] [INT] NULL,
CONSTRAINT [PK_dbo.InventoryItemCalendars] 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
ALTER TABLE [dbo].[InventoryItemCalendars] WITH CHECK ADD CONSTRAINT [FK_dbo.InventoryItemCalendars_dbo.InventoryItems_ItemId] FOREIGN KEY([ItemId])
REFERENCES [dbo].[InventoryItems] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[InventoryItemCalendars] CHECK CONSTRAINT [FK_dbo.InventoryItemCalendars_dbo.InventoryItems_ItemId]
GO
ALTER TABLE [dbo].[InventoryItemCalendars] WITH CHECK ADD CONSTRAINT [FK_dbo.InventoryItemCalendars_dbo.Projects_Project_Id] FOREIGN KEY([Project_Id])
REFERENCES [dbo].[Projects] ([Id])
GO
ALTER TABLE [dbo].[InventoryItemCalendars] CHECK CONSTRAINT [FK_dbo.InventoryItemCalendars_dbo.Projects_Project_Id]
GO
INSERT INTO ShipListInventory.[dbo].[InventoryItems]([PartSatuts],[PartId]) VALUES(1,1);
INSERT INTO ShipListInventory.[dbo].[InventoryItems]([PartSatuts],[PartId]) VALUES(2,1);
INSERT INTO ShipListInventory.[dbo].[InventoryItems]([PartSatuts],[PartId]) VALUES(1,1);
INSERT INTO ShipListInventory.[dbo].[InventoryItems]([PartSatuts],[PartId]) VALUES(4,1);
INSERT INTO ShipListInventory.[dbo].[InventoryItemCalendars](StartDate,InboundDate,Project_Id, ItemId)VALUES('1/1/2015', '4/15/2015',1,1)
INSERT INTO ShipListInventory.[dbo].[InventoryItemCalendars](StartDate,InboundDate,Project_Id, ItemId)VALUES('1/1/2015', '4/15/2015',1,1)
INSERT INTO ShipListInventory.[dbo].[InventoryItemCalendars](StartDate,InboundDate,Project_Id, ItemId)VALUES('1/1/2015', '4/14/2015',1,2)
INSERT INTO ShipListInventory.[dbo].[InventoryItemCalendars](StartDate,InboundDate,Project_Id, ItemId)VALUES('1/1/2015', '4/15/2015',1,1)
this isnt returning data from correct table it is only returning data form InventoryItemCalendars which isnt what i want. i want it to only use this to check the dates. it should return the items from InventoryItems table

Here is a syntactically correct version:
SELECT SUM(CASE WHEN ii.[PartStatus] = 1 THEN 1 ELSE 0 END) AS [Available],
SUM(CASE WHEN ii.[PartStatus] = 2 THEN 1 ELSE 0 END) AS [Reserverd],
SUM(CASE WHEN ii.[PartStatus] <> 4 THEN 1 ELSE 0 END) AS [TotalInventory]
FROM ShipListInventory.dbo.InventoryItems ii LEFT JOIN
ShipListInventory.dbo.InventoryItemCalendars AS iic
ON iic.[ItemId] = ii.[Id]
WHERE iic.[StartDate] NOT BETWEEN #startDate AND #endDate AND
iic.[InboundDate] NOT BETWEEN #startDate AND #endDate AND
ii.[PartId] = 248;
There is no transaction when you do a select, so committing is not necessary.

SELECT COUNT(CASE WHEN ii.[PartStatus] = 1 THEN ii.[PartId] END) AS [Available],
COUNT(CASE WHEN ii.[PartStatus] = 2 THEN ii.[PartId] END) AS [Reserverd],
COUNT(CASE WHEN ii.[PartStatus] <> 4 THEN ii.[PartId] END) AS [TotalInventory]

With the help of Juan Carlos I have found the correct answer.
SELECT COUNT(CASE WHEN ii.[PartSatuts]=1 THEN ii.[PartId] END ) AS [Available],
COUNT(CASE WHEN ii.[PartSatuts]=2 THEN ii.[PartId] END ) AS [Reserverd],
COUNT(CASE WHEN ii.[PartSatuts]<> 4 THEN ii.[PartId] END ) AS [TotalInventory]
FROM ShipListInventory.dbo.InventoryItems AS ii
LEFT JOIN ShipListInventory.dbo.InventoryItemCalendars AS iic
ON iic.ItemId = ii.Id
WHERE ((iic.StartDate NOT BETWEEN #startDate AND #endDate
AND iic.InboundDate NOT BETWEEN #startDate AND #endDate)
OR iic.InboundDate IS NULL)
AND ii.PartId = 248

Related

Bypass duplicate record when one table data is inserted from another in SQL Server

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 .

SQL Descending ordered LEFT JOIN subquery issue

I have the following query.
SELECT r1.*,
r2.vlag54,
r2.vlag55
FROM [rxmon].[dbo].[a] AS r1
LEFT JOIN [rxmon].[dbo].[b] AS r2
ON r2.artikelnummer = r1.drug_id
LEFT JOIN (SELECT *
FROM [rxmon].[dbo].[c]) AS r3
ON r3.pid = r1.patient_id
WHERE r3.obx_id = 20937
AND Cast(r3.obx_datetime AS DATE) = Cast(Getdate() - 1 AS DATE)
AND r1.patient_id = 7092425
AND obx_value < CASE
WHEN r2.vlag54 = 1 THEN 30
WHEN r2.vlag55 = 1 THEN 50
END
AND r2.vlag54 = CASE
WHEN r3.obx_value < 30 THEN 1
ELSE 0
END
AND r2.vlag55 = CASE
WHEN r3.obx_value BETWEEN 30 AND 50 THEN 1
ELSE 0
END
ORDER BY obx_datetime DESC;
The problem is that table C can contain multiple records based on de PID join. This generates the same records because of the multiple records on table C.
The table C needs to e joined as the latest record only so just 1 of C. That way the table A record will not be repeated.
I tried TOP 1 and order by but that can't be used in subquery.
-- TABLE A
CREATE TABLE [dbo].[A]
[EVS_MO_ID] [bigint] NOT NULL,
[DRUG_ID] [varchar](50) NOT NULL,
[ATC_CODE] [varchar](15) NULL,
[DRUG_NAME] [varchar](1024) NULL,
[PATIENT_ID] [varchar](50) NOT NULL,
[PATIENT_LOCATION] [varchar](10) NULL,
[MO_DATE] [datetime2](7) NOT NULL,
[MO_START_DATE] [datetime2](7) NOT NULL,
[MO_STOP_DATE] [datetime2](7) NULL,
[ROUTE] [varchar](50) NULL,
[MEDICATION_CONTAINER] [smallint] NULL,
[PRESCRIBING_DOCTOR_NAME] [varchar](50) NULL,
[PRESCRIBING_DOCTOR_SURNAME] [varchar](50) NULL,
[MO_ACTIVE] [bit] NOT NULL,
CONSTRAINT [PK_MedicationOrders] PRIMARY KEY CLUSTERED
(
[EVS_MO_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [dbo].[A]
VALUES
(5411409,'97941689', 'B01AB06','NADROPARINE 0.8ML','7092425','ANBC', '2015-12-15 20:58:06.2030000',
'2015-12-16 00:00:00.0000000', '', 'IV', 1, 'GEORGE','LAST', 1);
-- TABLE B
CREATE TABLE [dbo].[B](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ARTIKELNUMMER] [varchar](50) NOT NULL,
[VLAG54] [bit] NULL,
[VLAG55] [bit] NULL CONSTRAINT [DF_Table_1_VLAG50] DEFAULT ((0)),
[VLAG100] [bit] NULL CONSTRAINT [DF_ArtikelVlaggen_VLAG100] DEFAULT ((0)),
CONSTRAINT [PK_B] 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]
INSERT INTO [dbo].[B]
([ARTIKELNUMMER]
,[VLAG54]
,[VLAG55]
,[VLAG100])
VALUES
('97941689', 1,0,1);
-- TABLE C
CREATE TABLE [dbo].[C](
[ID] [int] IDENTITY(1,1) NOT NULL,
[OBX_DATETIME] [datetime2](7) NOT NULL,
[PID] [int] NOT NULL,
[DEPARTMENT] [varchar](8) NOT NULL,
[OBX_ID] [int] NOT NULL,
[OBX_VALUE] [decimal](5, 2) NOT NULL,
[OBX_UNITS] [varchar](10) NULL,
[REF_RANGE] [varchar](40) NULL,
[FLAG] [varchar](2) NULL,
CONSTRAINT [PK_C] 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]
INSERT INTO [dbo].[C]
([OBX_DATETIME]
,[PID]
,[DEPARTMENT]
,[OBX_ID]
,[OBX_VALUE]
,[OBX_UNITS]
,[REF_RANGE]
,[FLAG])
VALUES
('2015-12-15 14:01:00.0000000',7092425, '8NAH', 20937, 27.00, 'mL/min', '> 60', 'L');
INSERT INTO [dbo].[C]
([OBX_DATETIME]
,[PID]
,[DEPARTMENT]
,[OBX_ID]
,[OBX_VALUE]
,[OBX_UNITS]
,[REF_RANGE]
,[FLAG])
VALUES
('2015-12-15 06:30:00.0000000',7092425, '6ZPA', 20937, 28.00, 'mL/min', '> 60', 'L');
This will order them by OBX_DATETIME and take only the first one:
...
LEFT JOIN (
SELECT pid, obx_id, obx_datetime, obx_value
, n = ROW_NUMBER() over(PARTITION BY pid ORDER BY obx_datetime desc)
FROM [rxmon].[dbo].[c]
) AS r3
ON r3.pid = r1.patient_id and r3.n = 1
...
If OBX_DATETIME are inserted incrementaly (newer date only), you can order by ID instead.
This SQL Fiddle with your query and sample data/tables returns 2 rows: http://sqlfiddle.com/#!3/df36c/2/0
This SQL Fiddle with the new subquery returns 1 row: http://sqlfiddle.com/#!3/df36c/1/0
You are using a LEFT JOIN on r3 but have also have r3 in your WHERE clause with equal operator:
WHERE r3.obx_id = 20937
AND Cast(r3.obx_datetime AS DATE) = Cast(Getdate() - 1 AS DATE)
It will remove NULL value from the left join on r3. Perhaps you should also move it to the sub query or use INNER JOIN.
You should also avoind using the DB name in your query unless this query is run from another DB on the same server. This will be fine:
SELECT ... FROM [dbo].[a] AS r1 ...
Using SELECT * is also a bad habit. You should list only the columns your code will use.
try this.... #Shift
SELECT r1.*,
r2.vlag54,
r2.vlag55
FROM [dbo].[a] AS r1
LEFT JOIN [dbo].[b] AS r2
ON r2.artikelnummer = r1.drug_id
LEFT JOIN (
SELECT
ROW_NUMBER() OVER (PARTITION BY pid ORDER BY id DESC) RN,
c.*
FROM C
) r3
ON r3.pid = r1.patient_id AND r3.RN = 1
WHERE r3.obx_id = 20937
AND Cast(r3.obx_datetime AS DATE) = Cast(Getdate() - 1 AS DATE)
AND r1.patient_id = 7092425
AND obx_value < CASE
WHEN r2.vlag54 = 1 THEN 30
WHEN r2.vlag55 = 1 THEN 50
END
AND r2.vlag54 = CASE
WHEN r3.obx_value < 30 THEN 1
ELSE 0
END
AND r2.vlag55 = CASE
WHEN r3.obx_value BETWEEN 30 AND 50 THEN 1
ELSE 0
END
ORDER BY obx_datetime DESC;

Why do I get sql error "Violation of PRIMARY KEY constraint"

I have a table
CREATE TABLE [dbo].[DocGenVariable](
[userkey_sessionid] [varchar](38) NOT NULL,
[is_session] [bit] NULL,
[var_name] [nvarchar](255) NOT NULL,
[var_value] [nvarchar](1000) NOT NULL,
[topic_id] [varchar](38) NOT NULL,
[resource_id] [int] NULL,
[added] [datetime] NOT NULL,
CONSTRAINT [PK_DocGenVariable] PRIMARY KEY CLUSTERED
(
[userkey_sessionid] ASC,
[var_name] ASC,
[topic_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]
Sometimes (attention > sometimes) I get an error
"Violation of PRIMARY KEY constraint 'PK_DocGenVariable'.
Cannot insert duplicate key in object 'dbo.DocGenVariable'.
when I try to add an entry into this table
delete from DocGenVariable where userkey_sessionid = #key_session and var_name = #var_name and topic_id = #topic_id
if (LTRIM(RTRIM(#var_value)) <> '')
begin
insert into DocGenVariable(userkey_sessionid, is_session, var_name, var_value, topic_id, resource_id, added)
values (#key_session, #is_session, #var_name, #var_value, #topic_id, #resource_id, GetDate())
end
What I do first is deleting an entry which must be updated, then add a new entry.
Why do I get this constraint error?
Why delete then insert? Just update it.
IF EXISTS(select 1 from DocGenVariable where userkey_sessionid = #key_session
and
var_name = #var_name and topic_id = #topic_id)
BEGIN
UPDATE ....
END ELSE BEGIN
INSERT ...
END
Try upsert
using DocGenVariable target
using DocGenVariable source
on source.userkey_sessionid = #key_session
and source.var_name = #var_name
and source.topic_id = #topic_id
and target.userkey_sessionid = #key_session
and target.var_name = #var_name
and target.topic_id = #topic_id
when match
set target.resource_id = #resource_id
, target .added = GetDate()
when not matched then
insert into DocGenVariable(userkey_sessionid, is_session, var_name, var_value, topic_id, resource_id, added)
values (#key_session, #is_session, #var_name, #var_value, #topic_id, #resource_id, GetDate())

In a SQL Query, How do I do a join only on specific conditions?

I have the following SQL Query:
select Subjects.S_ID as ID,
Subjects.S_ParentID as ParentID,
Subjects.S_Name as Name,
Subjects.S_Order as [Order],
subjects.Sbj_IsVisible
from Subjects
left join KPI_SubjectDetails k on Subjects.S_ID = k.S_ID
where
subjects.Sbj_CourseID = 7594
and subjects.Sbj_Type=2
and subjects.Sbj_IsVisible=1
order by subjects.S_Level,
k.SD_Order
Each Subject has a s_ParentID. The most top subjects have a s_ParnetID of 0.
I want to add a SQL Join, which will do the following:
If a parent Subject is set to Sbj_IsVisible = 0 (any subject can be a parent), then the SQL should not output it or any of its children. However, if s_ParentID is set to 0, I don't want to do the Sbj_IsVisible check as this is the top most subject.
Here's what I got:
select Subjects.S_ID as ID,
Subjects.S_ParentID as ParentID,
Subjects.S_Name as Name,
Subjects.S_Order as [Order],
subjects.Sbj_IsVisible
from Subjects
join Subjects_tbl st on Subjects.S_ParentID = st.S_ID and subjects.S_ParentID <> 0
left join KPI_SubjectDetails k on Subjects.S_ID = k.S_ID
where
subjects.Sbj_CourseID = 7594
and subjects.Sbj_Type=2
and subjects.Sbj_IsVisible=1
and st.Sbj_IsVisible = 1
order by subjects.S_Level,
k.SD_Order
This partly works. When a parent subject is set to sbj_Isvisible 0, it does not return its children.
However, if the top most subject is set to sbj_IsVisible 1, the top most subject does not output, but its children do.
BTW, This is one a SQL Server 2008.
//edit
adding some example data.
This is the output of the original query:
ID ParentID Name Order Sbj_IsVisible
9017 0 'Boot Camp' 18 1
9033 9017 1 4 1
9049 9017 test 1 8 1
9050 9049 test 2 1 1
and this is the output of my query:
ID ParentID Name Order Sbj_IsVisible
9033 9017 1 4 1
9049 9017 test 1 8 1
9050 9049 test 2 1 1
here's the create table output:
USE [Fox8]
GO
/****** Object: Table [dbo].[Subjects_tbl] Script Date: 02/22/2012 16:25:12 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Subjects_tbl](
[S_ID] [int] IDENTITY(1,1) NOT NULL,
[S_TopID] [int] NULL,
[S_ParentID] [int] NULL,
[S_Name] [nvarchar](255) NULL,
[S_Order] [int] NULL,
[S_ItemCount] [int] NOT NULL,
[S_Level] [int] NULL,
[S_IsInherited] [int] NOT NULL,
[S_SortType] [nvarchar](50) NULL,
[S_SortOrder] [nvarchar](50) NULL,
[OriginalSbj_CourseID] [int] NULL,
[Sbj_CourseID] [int] NOT NULL,
[Sbj_IsVisible] [int] NULL,
[Sbj_SkinType] [int] NULL,
[CopyOf_SubjectID] [int] NULL,
[Sbj_GUID] [uniqueidentifier] NULL,
[Sbj_type] [int] NULL,
[s_OriginalSubjectID] [int] NULL,
[OriginalEvalTree_SbjId] [int] NULL,
[S_IsDeleted] [smallint] NOT NULL,
[S_DateDeleted] [datetime] NULL,
[S_IsPrimary] [bit] NULL,
CONSTRAINT [PK_Subjects] PRIMARY KEY CLUSTERED
(
[S_ID] ASC,
[S_ItemCount] ASC,
[Sbj_CourseID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UX_Subjects_S_ID_Sbj_CourseID] UNIQUE NONCLUSTERED
(
[S_ID] ASC,
[Sbj_CourseID] 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
EXEC sys.sp_addextendedproperty #name=N'MS_Description', #value=N'bitwise field 1 for regular subject 2 for weighted Subject 4 for X of Y Subject' , #level0type=N'SCHEMA',#level0name=N'dbo', #level1type=N'TABLE',#level1name=N'Subjects_tbl', #level2type=N'COLUMN',#level2name=N'Sbj_type'
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD CONSTRAINT [DF_Subjects_S_ItemCount] DEFAULT ((0)) FOR [S_ItemCount]
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD CONSTRAINT [DF_Subjects_S_IsInherited] DEFAULT ((1)) FOR [S_IsInherited]
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD CONSTRAINT [DF_Subjects_Sbj_CourseID] DEFAULT ((-1)) FOR [Sbj_CourseID]
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD DEFAULT ((0)) FOR [Sbj_SkinType]
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD CONSTRAINT [DF_Subjects_Sbj_IsEvaluation] DEFAULT ((1)) FOR [Sbj_type]
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD DEFAULT ((0)) FOR [S_IsDeleted]
GO
ALTER TABLE [dbo].[Subjects_tbl] ADD DEFAULT ((0)) FOR [S_IsPrimary]
GO
Your question is a little confusing to me but let me suggest using an OR clause, as in:
SELECT s.S_ID AS ID, s.S_ParentID AS ParentID, s.S_Name AS Name,
s.S_Order AS [Order], s.Sbj_IsVisible
FROM Subjects s
LEFT JOIN Subjects_tbl st ON s.S_ParentID = st.S_ID
LEFT JOIN KPI_SubjectDetails k ON s.S_ID = k.S_ID
WHERE s.Sbj_CourseID = 7594
AND s.Sbj_Type=2
AND s.Sbj_IsVisible = 1
AND (st.Sbj_IsVisible = 0 OR s.S_ParentID = 0)
ORDER BY s.S_Level, k.SD_Order
Essentially, select information from the subjects table if either it's corresponding parent is not visible or it does not have a corresponding parent (along with whatever your other conditions mean).
Hope that helps!

how can i make this proc better?

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