Dynamic column create from child table - sql

I have two table one for master and another child. Which is depicting below
Master table:
and scripts:
CREATE TABLE [dbo].[SET_HRShiftProfile](
[id] [smallint] NOT NULL,
[LocationID] [tinyint] NOT NULL,
[ShiftTypeID] [smallint] NOT NULL,
[ProfileName] [nvarchar](50) NULL,
[EmpTypeCode] [nvarchar](10) NOT NULL,
[IsActive] [bit] NOT NULL,
CONSTRAINT [PK_HR_ShiftProfile] 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
Child Table:
And script:
CREATE TABLE [dbo].[SET_HRShiftProfileDetail](
[id] [int] NOT NULL,
[LocationID] [tinyint] NOT NULL,
[ShiftprofileID] [smallint] NOT NULL,
[ShiftProfTypeCode] [nvarchar](10) NOT NULL,
[Start] [nvarchar](5) NULL,
[End] [nvarchar](5) NULL,
[ToleranceBefore] [nvarchar](5) NULL,
[ToleranceAfter] [nvarchar](5) NULL,
CONSTRAINT [PK_SET_HRShiftProfileDetail] 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
I need to final query result look like this, means all child table row will be column for master table
Any idea give me appreciate. Thanks.

Try this:
with pivoted as
(
select LocationID, ShiftprofileID, [IN], [OUT], [Break]
from (
select distinct LocationID, ShiftprofileID, [ShiftProfTypeCode]
from [dbo].[SET_HRShiftProfileDetail]
) as t
pivot (
count([ShiftProfTypeCode]) for [ShiftProfTypeCode] in ([IN], [OUT], [Break])
) as p
)
select p.*
, x.[IN], x.[OUT], x.[Break]
from [dbo].[SET_HRShiftProfile] as p
left join pivoted x on x.ShiftprofileID = p.id
and x.locationid = p.locationid
Results:
id LocationID ShiftTypeID ProfileName EmpTypeCode IsActive IN OUT Break
1003 1 1001 Day-Summar REG 1 1 1 1
1006 1 1005 Say-Winter REG 1 1 1 0
Since you said nothing about what data you like to get into cells, I have placed there the count of rows with such value (as column name) from the child table.
Hope it will help you to solve your problem
LATER EDIT
Solution without using PIVOT:
with pivoted as
(
select LocationID
, ShiftprofileID
, sum(case when [ShiftProfTypeCode] = 'OUT' then 1 else 0 end) [OUT]
, sum(case when [ShiftProfTypeCode] = 'IN' then 1 else 0 end) [IN]
, sum(case when [ShiftProfTypeCode] = 'Break' then 1 else 0 end) [Break]
from [dbo].[SET_HRShiftProfileDetail]
group by LocationID, ShiftprofileID
)
select p.*
, x.[IN], x.[OUT], x.[Break]
from [dbo].[SET_HRShiftProfile] as p
left join pivoted x on x.ShiftprofileID = p.id
and x.locationid = p.locationid
Results:
id LocationID ShiftTypeID ProfileName EmpTypeCode IsActive IN OUT Break
1003 1 1001 Day-Summar REG 1 1 1 1
1006 1 1005 Say-Winter REG 1 1 1 0

Related

How To Improve Performance of Sql Query with Union

Below query takes almost 47-50 seconds on our production server, but when I execute the same on a test server with the same database, it executes in less than a second.
CREATE TABLE [dbo].[Table0]
(
[UserID] [VARCHAR](20) NOT NULL,
[Key] [VARCHAR](600) NOT NULL,
[Type] [VARCHAR](20) NOT NULL,
[status] [VARCHAR](10) NOT NULL,
[RecID] [NUMERIC](18, 0) NOT NULL,
CONSTRAINT [PK_Table0]
PRIMARY KEY CLUSTERED ([UserID] ASC, [Key] ASC, [Type] ASC, [status], [RecID] 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].[Table2]
(
[UserID] [VARCHAR](20) NOT NULL,
[RecID] [NUMERIC](18, 0) NOT NULL,
[Activity] [NUMERIC](2, 0) NOT NULL,
[AwsExist] [NUMERIC](2, 0) NULL,
[View] [NUMERIC](2, 0) NULL,
CONSTRAINT [PK_Table2]
PRIMARY KEY CLUSTERED ([UserID] ASC, [RecID] ASC, [Activity] 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].[Table3]
(
[UserID] [VARCHAR](20) NOT NULL,
[RecId] [NUMERIC](18, 0) NOT NULL,
[Activity] [NUMERIC](2, 0) NOT NULL,
[AwsExist] [NUMERIC](2, 0) NULL,
[RecDate] [DATETIME] NULL,
[View] [NUMERIC](2, 0) NULL,
CONSTRAINT [PK_Table3]
PRIMARY KEY CLUSTERED ([UserID] ASC, [RecId] ASC, [Activity] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Table0 contains 10,000 Records
Table1 contains 20,00,000 records
Table2 contains 25,00,000 records
which parameter should I check to resolve the issue? I just want to check if a record exists in one of these table for RecID
Select UserID From Table0 Where RecId = 56445 And Type = 'D'
Union
Select UserID From Table1 Where RecId = 56445 And View = 0
Union
Select UserID From Table2 Where RecId = 56445 And View = 0
I tried with this code:
DECLARE RecID AS INT
SET RecID = 56445
IF NOT EXISTS (SELECT DISTINCT TOP(1) USerID
FROM Table0
WHERE RecId = #RecID
AND Type = 'D')
BEGIN
IF NOT EXISTS (SELECT DISTINCT TOP(1) UserID
FROM Table1
WHERE RecId = #RecID AND View = 0)
BEGIN
SELECT DISTINCT TOP(1) UserID
FROM Table2
WHERE RecId = #RecID AND View = 0
END
END
but it also takes around 18 seconds.
This query should be fast -- assuming not many rows are returned:
Select UserID From Table0 Where RecId = 56445 And Type = 'D'
Union
Select UserID From Table1 Where RecId = 56445 And View = 0
Union
Select UserID From Table2 Where RecId = 56445 And View = 0;
What you need are indexes:
Table0(recid, type, userid)
Table1(recid, view, userid)
Table2(recid, view, userid)
You may have to use query like:
Select UserID
From table0
Where exists (
Select 1
From Table0 t0, Table1 t1, Table2 t2
Where (t0.RecId = 56445 and t0.Type= 'D') OR (t1.RecId = 56445 and t1.View= 0) OR (t2.RecId = 56445 AND t2.View=0))

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;

get rows and rows from one table SQL server

i have comments table in sql server structured as
CREATE TABLE [dbo].[LS_Commentes](
[CommentId] [int] IDENTITY(1,1) NOT NULL,
[OwnerId] [uniqueidentifier] NULL,
[OwnerName] [nvarchar](50) NULL,
[Email] [nvarchar](250) NULL,
[Date] [nvarchar](15) NULL,
[ParentId] [int] NULL,
[CommentText] [nvarchar](400) NULL,
[ItemId] [int] NULL,
[upVotes] [int] NULL,
[downVotes] [int] NULL,
[isApproved] [bit] NULL,
CONSTRAINT [PK_LS_MsgCommentes] PRIMARY KEY CLUSTERED
(
[CommentId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
and i have sample data like this:
CommentId OwnerId OwnerName Email Date ParentId CommentText ItemId upVotes downVotes isApproved
1 NULL Test Commneter NULL 1/4/2013 NULL test 9 0 0 NULL
2 NULL Test Commneter NULL 1/4/2013 1 test NULL 0 0 NULL
3 NULL Test Commneter NULL 1/4/2013 1 test NULL 0 0 NULL
i want to write one query can get me all rows have itemid =9 and rows have parentid= comment id that selected (because itemid = 9)
look here i can solve it by adding item id 9 to the sub comments too but i just want to know if that could be solved without adding item id to comments and sub comments
I think the following query does what you want:
select *
from ls_comments c
where c.itemID = 9 or
c.parentID in (select c2.commentId from ls_comments c2 where c2.itemId = 9)
Would a recursive Common Table Expression give you the results you're after?
;with cte as
(
--Anchor
select
commentid,
ParentId
from
LS_Commentes
where
ItemId = 9
union all
--Recursive member
select
c.commentId,
c.ParentId
from
LS_Commentes c join cte on c.ParentId = cte.CommentId
)
select * from cte
If you want to include more columns in the results ensure that both parts (the Anchor and recursive member) have identical columns.
Explanation:
The anchor part (the first select) of a recursive query selects all rows where ItemId = 9, the second part uses the existing records in the result to include further records that satisfy it's criters (ParentId = cte.CommentId) this keeps going until nothing more is selected. And then the entire results must be selected at the end (after the CTEs definition)
I think it would be good with an embedded SQL query
SELECT *
FROM `LS_Commentes`
WHERE `ItemId` = '9'
AND `ParentID`= (SELECT `CommentID` FROM `LS_Commentes` WHERE `ItemId` = 9);

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