SQL Server XML Query Hierarchy not as awaited - sql-server

There are five or more database tables, that are related to each other like in the following database schema:
Here is the code for creating them:
-- Table 1
CREATE TABLE [dbo].[Table1](
[Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
[Annotation] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
-- Table 2 referencing Table 1
CREATE TABLE [dbo].[Table2](
[Id] [INT] NOT NULL,
[Table1_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table2] WITH CHECK ADD CONSTRAINT [FK_Table2_Table1] FOREIGN KEY([Table1_Id])
REFERENCES [dbo].[Table1] ([Id])
GO
ALTER TABLE [dbo].[Table2] CHECK CONSTRAINT [FK_Table2_Table1]
GO
-- Table 2_1 referencing Table 2
CREATE TABLE [dbo].[Table2_1](
[Id] [INT] NOT NULL,
[Table2_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table2_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table2_1] WITH CHECK ADD CONSTRAINT [FK_Table2_1_Table2] FOREIGN KEY([Table2_Id])
REFERENCES [dbo].[Table2] ([Id])
GO
ALTER TABLE [dbo].[Table2_1] CHECK CONSTRAINT [FK_Table2_1_Table2]
GO
-- Table 3 referencing Table 1
CREATE TABLE [dbo].[Table3](
[Id] [INT] NOT NULL,
[Table1_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table3] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table3] WITH CHECK ADD CONSTRAINT [FK_Table3_Table1] FOREIGN KEY([Table1_Id])
REFERENCES [dbo].[Table1] ([Id])
GO
ALTER TABLE [dbo].[Table3] CHECK CONSTRAINT [FK_Table3_Table1]
GO
-- Table 3_1 referencing Table 3
CREATE TABLE [dbo].[Table3_1](
[Id] [INT] NOT NULL,
[Table3_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table3_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table3_1] WITH CHECK ADD CONSTRAINT [FK_Table3_1_Table3] FOREIGN KEY([Table3_Id])
REFERENCES [dbo].[Table3] ([Id])
GO
ALTER TABLE [dbo].[Table3_1] CHECK CONSTRAINT [FK_Table3_1_Table3]
GO
Now I add the following record samples to the table:
INSERT INTO table1 VALUES (1, 'FirstTitle', 'FirstAnno')
INSERT INTO table2 VALUES (1, 1, 'Tab2Title')
INSERT INTO table3 VALUES (1, 1, 'Tab3Title')
INSERT INTO table2_1 VALUES (1, 1, 'Tab21Sub')
INSERT INTO table3_1 VALUES (1, 1, 'Tab31Sub')
Querying this tables with a JOIN FOR XML like
SELECT * FROM Table1 AS T1
JOIN Table2 AS T2 ON T1.Id = T2.Table1_Id
JOIN Table3 AS T3 ON T1.Id = T3.Table1_Id
JOIN Table2_1 AS T21 ON T2.Id = T21.Table2_Id
JOIN Table3_1 AS T31 ON T3.Id = T31.Table2_Id
FOR XML AUTO
will end in this result
<T1 Id="1" Title="FirstTitle" Annotation="FirstAnno ">
<T2 Id="1" Table1_Id="1" Title="Tab2Title ">
<T3 Id="1" Table1_Id="1" Title="Tab3Title ">
<T21 Id="1" Table2_Id="1" Title="Tab21Sub ">
<T31 Id="1" Table3_Id="1" Title="Tab31Sub " />
</T21>
</T3>
</T2>
</T1>
while I'm expecting this
<T1 Id="1" Title="FirstTitle" Annotation="FirstAnno ">
<T2 Id="1" Table1_Id="1" Title="Tab2Title ">
<T21 Id="1" Table2_Id="1" Title="Tab21Sub" />
</T2>
<T3 Id="1" Table1_Id="1" Title="Tab3Title ">
<T31 Id="1" Table3_Id="1" Title="Tab31Sub" />
</T3>
</T1>
So how can I modify the query, perhaps making subqueries to get the expected result, sorting Table 3 at the same level and not beneath table2, and also sorting the childs of table2_1 and table3_1 beneath there parents?

Given your hierarchical example I've fleshed out the example data to include some more subitems...
INSERT INTO table1 VALUES (1, 'FirstTitle', 'FirstAnno');
INSERT INTO table2 VALUES (1, 1, 'Tab2Title1');
INSERT INTO table2_1 VALUES (1, 1, 'Tab21Sub1.1');
INSERT INTO table2_1 VALUES (2, 1, 'Tab21Sub1.2');
INSERT INTO table2_1 VALUES (3, 1, 'Tab21Sub1.3');
INSERT INTO table2 VALUES (2, 1, 'Tab2Title2');
INSERT INTO table2_1 VALUES (4, 2, 'Tab21Sub2.1');
INSERT INTO table2_1 VALUES (5, 2, 'Tab21Sub2.2');
INSERT INTO table3 VALUES (1, 1, 'Tab3Title1');
INSERT INTO table3_1 VALUES (1, 1, 'Tab31Sub');
INSERT INTO table3 VALUES (2, 1, 'Tab3Title2');
If you use FOR XML AUTO and correlated subqueries that return FOR XML AUTO, TYPE such as the following:
SELECT T1.*,
(
SELECT T2.*,
(
SELECT T21.*
FROM Table2_1 AS T21
WHERE T2.Id = T21.Table2_Id
FOR XML AUTO, TYPE
)
FROM Table2 AS T2
WHERE T1.Id = T2.Table1_Id
FOR XML AUTO, TYPE
),
(
SELECT T3.*,
(
SELECT T31.*
FROM Table3_1 AS T31
WHERE T3.Id = T31.Table3_Id
FOR XML AUTO, TYPE
)
FROM Table3 AS T3
WHERE T1.Id = T3.Table1_Id
FOR XML AUTO, TYPE
)
FROM Table1 AS T1
FOR XML AUTO;
You can return nested XML data such as the following:
<T1 Id="1" Title="FirstTitle" Annotation="FirstAnno ">
<T2 Id="1" Table1_Id="1" Title="Tab2Title1">
<T21 Id="1" Table2_Id="1" Title="Tab21Sub1.1"/>
<T21 Id="2" Table2_Id="1" Title="Tab21Sub1.2"/>
<T21 Id="3" Table2_Id="1" Title="Tab21Sub1.3"/>
</T2>
<T2 Id="2" Table1_Id="1" Title="Tab2Title2">
<T21 Id="4" Table2_Id="2" Title="Tab21Sub2.1"/>
<T21 Id="5" Table2_Id="2" Title="Tab21Sub2.2"/>
</T2>
<T3 Id="1" Table1_Id="1" Title="Tab3Title1">
<T31 Id="1" Table3_Id="1" Title="Tab31Sub "/>
</T3>
<T3 Id="2" Table1_Id="1" Title="Tab3Title2"/>
</T1>

Related

MSSQL: How to join only if its children not exist

I want to left join but only if it does not have the specific child.
Here is my current query:
SELECT "chatRoom"."id" as id,
"chatRoom"."name" as name,
"chatRoom"."type" as type,
"chatRoom"."description" as description,
"chatRoom"."thumbnail" as thumbnail,
"chatRoom"."status" as status,
chats.[unreadCount] as unreadCount
FROM "chat_room" "chatRoom"
LEFT JOIN "chat_room_participant" "participants" ON "participants"."chatRoomId"="chatRoom"."id"
LEFT JOIN (
SELECT "chatRoom"."id" AS "chatRoomId", COUNT(readBy.id) AS "unreadCount"
FROM "chat" "chat"
LEFT JOIN "chat_room" "chatRoom" ON "chatRoom"."id"="chat"."chatRoomId"
LEFT JOIN "chat_read_by_chat_room_participant" "chat_readBy" ON "chat_readBy"."chatId"="chat"."id"
LEFT JOIN "chat_room_participant" "readBy" ON "readBy"."id"="chat_readBy"."chatRoomParticipantId"
WHERE NOT(readBy.UserId IN ('ca774a5f-a04d-ec11-ae58-74d83e04f9d3'))
OR "readBy"."id" IS NULL
GROUP BY "chatRoom"."id"
) "chats" ON chats.chatRoomId = "chatRoom"."id"
WHERE ('ALL' = 'ALL' OR "chatRoom"."status" = 'ALL')
AND "chatRoom"."applicationId" = '4ac752e9-004c-ec11-ae53-74d83e04f9d3'
AND "participants"."userId" = 'A97D66C4-014C-EC11-AE53-74D83E04F9D3'
ORDER BY "chatRoom"."lastUpdate" DESC
In this query, it returns the correct value only if the readBy is null or contains 1 entry which equals to the given userId.
So here I have the userId. I want to get all the unread chats count from each chatRoom that has the user as a participant.
The schema is like this:
chatRoom has many chats
chatRoom has many participants
chats has many to many `readBy` (participants)
So there is a column automatically created for the many-to-many relation:
column: chat_read_by_chat_room_participant
Contains:
|chatId|chatRoomParticipantId|
In my query above, the left join will get any readBy from another user:
WHERE NOT(readBy.UserId IN ('ca774a5f-a04d-ec11-ae58-74d83e04f9d3')) OR "readBy"."id" IS NULL GROUP BY "chatRoom"."id") "chats" ON chats.chatRoomId = "chatRoom"."id"
which I do not want. This will return the entry if the user already read the chat, but another users have read as well. I want to return the entry only if the user has not read the chat.
How can I do this?
CREATION QUERY
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[chat](
[id] [uniqueidentifier] NOT NULL,
[sentAt] [bigint] NOT NULL,
[type] [nvarchar](255) NOT NULL,
[status] [nvarchar](255) NOT NULL,
[message] [nvarchar](max) NOT NULL,
[filePath] [nvarchar](max) NULL,
[chatRoomId] [uniqueidentifier] NOT NULL,
[senderId] [nvarchar](255) NOT NULL,
[userId] [uniqueidentifier] NULL,
CONSTRAINT [PK_9d0b2ba74336710fd31154738a5] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[chat] ADD CONSTRAINT [DF_9d0b2ba74336710fd31154738a5] DEFAULT (newsequentialid()) FOR [id]
GO
ALTER TABLE [dbo].[chat] WITH CHECK ADD CONSTRAINT [FK_52af74c7484586ef4bdfd8e4dbb] FOREIGN KEY([userId])
REFERENCES [dbo].[chat_room_participant] ([id])
GO
ALTER TABLE [dbo].[chat] CHECK CONSTRAINT [FK_52af74c7484586ef4bdfd8e4dbb]
GO
ALTER TABLE [dbo].[chat] WITH CHECK ADD CONSTRAINT [FK_e49029a11d5d42ae8a5dd9919a2] FOREIGN KEY([chatRoomId])
REFERENCES [dbo].[chat_room] ([id])
GO
ALTER TABLE [dbo].[chat] CHECK CONSTRAINT [FK_e49029a11d5d42ae8a5dd9919a2]
GO
CREATE TABLE [dbo].[chat_read_by_chat_room_participant](
[chatId] [uniqueidentifier] NOT NULL,
[chatRoomParticipantId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_f3dd24628d4644dd6e79bcd03d1] PRIMARY KEY CLUSTERED
(
[chatId] ASC,
[chatRoomParticipantId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[chat_read_by_chat_room_participant] WITH CHECK ADD CONSTRAINT [FK_011624ccd7e7b0281ef629f2930] FOREIGN KEY([chatId])
REFERENCES [dbo].[chat] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[chat_read_by_chat_room_participant] CHECK CONSTRAINT [FK_011624ccd7e7b0281ef629f2930]
GO
ALTER TABLE [dbo].[chat_read_by_chat_room_participant] WITH CHECK ADD CONSTRAINT [FK_2e33e3de9d7c91d426c09a24810] FOREIGN KEY([chatRoomParticipantId])
REFERENCES [dbo].[chat_room_participant] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[chat_read_by_chat_room_participant] CHECK CONSTRAINT [FK_2e33e3de9d7c91d426c09a24810]
GO
CREATE TABLE [dbo].[chat_room](
[id] [uniqueidentifier] NOT NULL,
[name] [nvarchar](255) NULL,
[type] [nvarchar](255) NOT NULL,
[thumbnail] [nvarchar](max) NULL,
[description] [nvarchar](max) NULL,
[status] [nvarchar](255) NOT NULL,
[applicationId] [uniqueidentifier] NOT NULL,
[lastUpdate] [bigint] NULL,
CONSTRAINT [PK_8aa3a52cf74c96469f0ef9fbe3e] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[chat_room] ADD CONSTRAINT [DF_8aa3a52cf74c96469f0ef9fbe3e] DEFAULT (newsequentialid()) FOR [id]
GO
ALTER TABLE [dbo].[chat_room] WITH CHECK ADD CONSTRAINT [FK_2226638e6b7665ec0259d246b2b] FOREIGN KEY([applicationId])
REFERENCES [dbo].[application] ([id])
GO
ALTER TABLE [dbo].[chat_room] CHECK CONSTRAINT [FK_2226638e6b7665ec0259d246b2b]
GO
CREATE TABLE [dbo].[chat_room_participant](
[id] [uniqueidentifier] NOT NULL,
[joinedAt] [bigint] NOT NULL,
[privilege] [nvarchar](255) NOT NULL,
[chatRoomId] [uniqueidentifier] NOT NULL,
[userId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_15913cf37a762fce4c8d6a32a42] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY],
CONSTRAINT [UQ_ae9630d66f6c5d12afd1a991fec] UNIQUE NONCLUSTERED
(
[chatRoomId] ASC,
[userId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[chat_room_participant] ADD CONSTRAINT [DF_15913cf37a762fce4c8d6a32a42] DEFAULT (newsequentialid()) FOR [id]
GO
ALTER TABLE [dbo].[chat_room_participant] WITH CHECK ADD CONSTRAINT [FK_9f718459ea81b5130f81980ca08] FOREIGN KEY([userId])
REFERENCES [dbo].[user] ([id])
GO
ALTER TABLE [dbo].[chat_room_participant] CHECK CONSTRAINT [FK_9f718459ea81b5130f81980ca08]
GO
ALTER TABLE [dbo].[chat_room_participant] WITH CHECK ADD CONSTRAINT [FK_fb664f48a4ec615ec5cce90a25d] FOREIGN KEY([chatRoomId])
REFERENCES [dbo].[chat_room] ([id])
GO
ALTER TABLE [dbo].[chat_room_participant] CHECK CONSTRAINT [FK_fb664f48a4ec615ec5cce90a25d]
GO
It looks like you just need a WHERE NOT EXISTS correlated subquery.
Don't be tempted to just use LEFT JOIN IS NULL syntax, it is generally less efficient, as it hides from the optimizer that you are doing an anti-join. Occasionally it can be useful though.
Further notes:
Don't quote column and table names unless you have to. And generally avoid names that need quoting.
Don't alias columns that don't need aliasing.
Choose short meaningful table aliases.
Basic formatting and good use of whitespace helps readability
Your LEFT JOIN chat_room_participant logically becomes an INNER JOIN because of the WHERE.
You don't need to re-join chat_room in the grouped subquery, you can just group by the join column.
You may want to use a grouped OUTER APPLY instead of that subquery. It is unlikely to get a different query plan, but it can be easier to read.
COUNT(SomeNotNullValue) is the same as COUNT(*)
('ALL' = 'ALL' OR cr.status = 'ALL') only makes sense if cr.Status is nullable, otherwise you would just use cr.status = 'ALL'. Even if it is nullable, you may as well use (cr.Status IS NULL OR cr.status = 'ALL')
SELECT
cr.id,
cr.name,
cr.type,
cr.description,
cr.thumbnail,
cr.status,
c.unreadCount
FROM chat_room cr
JOIN chat_room_participant p ON p.chatRoomId = cr.id
LEFT JOIN (
SELECT
c.chatRoomId AS chatRoomId,
COUNT(*) AS unreadCount
FROM chat c
WHERE NOT EXISTS (SELECT 1
FROM chat_read_by_chat_room_participant chat_readBy
JOIN chat_room_participant readBy ON readBy.id = chat_readBy.chatRoomParticipantId
WHERE chat_readBy.chatId = c.id
AND readBy.UserId IN ('ca774a5f-a04d-ec11-ae58-74d83e04f9d3')
)
GROUP BY c.chatRoomId
) c ON c.chatRoomId = cr.id
WHERE (cr.Status IS NULL OR cr.status = 'ALL')
AND cr.applicationId = '4ac752e9-004c-ec11-ae53-74d83e04f9d3'
AND p.userId = 'A97D66C4-014C-EC11-AE53-74D83E04F9D3'
ORDER BY
cr.lastUpdate DESC;
It seems that what you want is an anti-semi join. That is, a join to demonstrate that a row does not exist.
The two typical methods are...
main_table AS m
LEFT JOIN
other_table AS o
ON o.m_id = m.id
AND o.user = 'xyz'
WHERE
o.id IS NULL
Or...
main_table AS m
WHERE
NOT EXISTS (
SELECT *
FROM other_table AS o
WHERE o.m_id = m.id
AND o.user = 'xyz'
)
Exactly how to apply this to your example is unclear as you have cluttered your question with too many other details. (It is not a Minimal Verifiable Example.)

Auditing SQL Server - who is changing what and when? SOX complaince

In my organization, we are doing very limited logging or any sort to capture who is changing what and when.
I am seeking help here to understand what should be the best practices to capture any logging whatsoever happening in our SQL Server database.
I am thinking of going over the tables based on the important business uses cases that a user can perform with the application and then making an xl file with the following fields so that I keep this file as a reference for myself.
My question: is there any other better way to capture the current change in the database, and is there a way in SQL Server that I use to find out if we are capturing any logging in the database?
We don't have any CDC implementation or C2 audit tracing enables or change tacking enabled.
Management want's to leverage the data captured in the database tables.
I am working on a similar project, you can use below design, i am explaining with student subject example
CREATE TABLE [dbo].[AudRel](
[AudId] [int] IDENTITY(1,1) NOT NULL,
[AudTableName] [varchar](100) NULL,
[AudFieldName] [varchar](100) NULL,
[AudFieldID] [varchar](30) NULL,
CONSTRAINT [PK_AuditRel] PRIMARY KEY CLUSTERED
(
[AudId] 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].[Student](
[StudentID] [int] IDENTITY(1,1) NOT NULL,
[StudentName] [varchar](100) NULL,
CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED
(
[StudentID] 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].[Student_Audit](
[ID] [int] IDENTITY(1,1) NOT NULL,
[StudentID] [int] NOT NULL,
[StudentName] [varchar](100) NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[StudentSubject](
[SSID] [int] IDENTITY(1,1) NOT NULL,
[StudentID] [int] NULL,
[SubjectID] [int] NULL,
CONSTRAINT [PK_StudentSubject] PRIMARY KEY CLUSTERED
(
[SSID] 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].[StudentSubject_Audit](
[ID] [int] IDENTITY(1,1) NOT NULL,
[SSID] [int] NOT NULL,
[StudentID] [int] NULL,
[SubjectID] [int] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[Subject](
[SubjectID] [int] IDENTITY(1,1) NOT NULL,
[SubjectName] [varchar](50) NULL,
CONSTRAINT [PK_Subject] PRIMARY KEY CLUSTERED
(
[SubjectID] 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].[Subject_Audit](
[ID] [int] IDENTITY(1,1) NOT NULL,
[SubjectID] [int] NOT NULL,
[SubjectName] [varchar](50) NULL
) ON [PRIMARY]
SET IDENTITY_INSERT [dbo].[AudRel] ON
INSERT [dbo].[AudRel] ([AudId], [AudTableName], [AudFieldName], [AudFieldID]) VALUES (1, N'Student', N'StudentName', N'StudentID')
INSERT [dbo].[AudRel] ([AudId], [AudTableName], [AudFieldName], [AudFieldID]) VALUES (2, N'Subject', N'SubjectName', N'SubjectID')
SET IDENTITY_INSERT [dbo].[AudRel] OFF
SET IDENTITY_INSERT [dbo].[Student] ON
INSERT [dbo].[Student] ([StudentID], [StudentName]) VALUES (1, N'Alex')
INSERT [dbo].[Student] ([StudentID], [StudentName]) VALUES (2, N'DSouza')
SET IDENTITY_INSERT [dbo].[Student] OFF
SET IDENTITY_INSERT [dbo].[StudentSubject] ON
INSERT [dbo].[StudentSubject] ([SSID], [StudentID], [SubjectID]) VALUES (1, 1, 1)
INSERT [dbo].[StudentSubject] ([SSID], [StudentID], [SubjectID]) VALUES (2, 2, 1)
INSERT [dbo].[StudentSubject] ([SSID], [StudentID], [SubjectID]) VALUES (3, 2, 2)
SET IDENTITY_INSERT [dbo].[StudentSubject] OFF
SET IDENTITY_INSERT [dbo].[Subject] ON
INSERT [dbo].[Subject] ([SubjectID], [SubjectName]) VALUES (1, N'English')
INSERT [dbo].[Subject] ([SubjectID], [SubjectName]) VALUES (2, N'Mathematics')
SET IDENTITY_INSERT [dbo].[Subject] OFF
and then use below query to dynamically fetch fields have been changed. From the UI you need to pass the AudRelID
DECLARE #TableName VARCHAR(100),#FieldName VARCHAR(100),#FieldID VARCHAR(100)
SELECT #TableName = [AudTableName]
, #FieldName=[AudFieldName]
, #FieldID=[AudFieldID]
FROM [dbo].[AudRel] WHERE [AudId] = 1 -- (Ex : StudentHistory)
DECLARE #SQL NVARCHAR(MAX) = N'
SELECT ID,' + #FieldID +
',' + #FieldName + ' FROM ' + #TableName + '_Audit ' + ' WHERE ' + #FieldID + ' = '
+ Convert(varchar(20),#FieldID)
print #SQL
EXECUTE sp_executesql #SQL

UNIQUE constraint exception thrown on empty table INSERT [sql-server]

My INSERT statement fails while it is trying to add a new record into an empty table (Attribute) (no record yet).
I am surprised by the error raised by the system:
Violation of UNIQUE KEY constraint 'CK_Attribute_Name_IDproject'. Cannot insert duplicate key in object 'dbo.Attribute'. The duplicate key value is (dummy, 55).
The creation script for this table looks like
CREATE TABLE [dbo].[Attribute](
[ID] [int] IDENTITY(1,1) NOT NULL,
[IDproject] [int] NOT NULL,
[IDtype] [int] NOT NULL,
[IDgroup] [int] NOT NULL,
[name] [varchar](50) NOT NULL,
[color] [int] NULL,
[protected] [tinyint] NULL,
[datemodified] [datetime] NOT NULL,
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],
CONSTRAINT [CK_Attribute_Name_IDproject] UNIQUE NONCLUSTERED
(
[name] ASC,
[IDproject] 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 skiped foreign keys references and default values which does not seem of interest in this context.
The UNIQUE constraint applies to [name] and [IDproject].
When running the following statement
SELECT *
FROM [dbo].[Attribute]
GO
SELECT *
FROM [dbo].[Project]
GO
I get the results
(0 row(s) affected)
(2 row(s) affected)
The first result indicats the Attribute Table is empty
The second that there are 2 Projects
then running the following INSERT in table Attribute it failed with the above mentioned UNIQUE CONSTRAINT error
INSERT INTO [dbo].[Attribute] ([IDproject], [name], [IDtype], [IDgroup], [color], [protected], [datemodified])
SELECT DISTINCT
p.[ID],'dummy',t.[ID],g.[ID],-1,0,getdate()
FROM [dbo].[Project] p
INNER JOIN [dbo].[Group] g ON g.[name]='none' AND g.[IDproject] = p.[ID]
INNER JOIN [dbo].[AttributeType] t ON t.[format]='text' AND g.[IDproject] = p.[ID]
WHERE p.[name]='TESTPROJ'
GO
How can i get such an error on an empty table ?
I have found the solution myself: the derived SELECT returns 2 records with 'dummy' due to a duplicate INTO one of table, AttributeType, with which INNER JOIN is performed.

Unable to apply a constraint when data in a column for multiple rows need to be kept unique for a particular foreign key's reference

Let me explain this scenario, with my table structure-
RoomId RoomMemberId
R1 RM1
R1 RM2
R1 RM3
R2 Rm1
R2 RM2
R3 RM1
R3 RM4
R3 RM3
Here in the above table RM1,RM2 and RM3 are the member of R1 room ,
now I have to apply a constraint that there should not be any other room where only these three are members
i.e. there should not be any other room with same room members.
How can i do it at database end, by any unique constraint or any other way to do so ??
Pls help...
Example of Constraint is as given below :
Sample Table
CREATE TABLE TBLROOMTEST
(
ROOMID VARCHAR(100),
ROOMMEMBERID VARCHAR(100)
)
Create function
CREATE FUNCTION dbo.fn_RoomMemberCheck (#room_id varchar(100), #room_member varchar(100))
RETURNS int
AS
BEGIN
DECLARE #retval int
SELECT #retval = CASE WHEN ROOMID = #room_id THEN 1 ELSE 0 END
FROM TBLROOMTEST WHERE ROOMMEMBERID = #room_member
RETURN #retval
END;
Add constraint after table creation(but this can be done at the time of table creation itself):
ALTER TABLE TBLROOMTEST
ADD CONSTRAINT chk_IfMemberExistsInRoom CHECK (dbo.fn_RoomMemberCheck(ROOMID,ROOMMEMBERID)=0);
Note : It will give you error if you already have data in your table, thats why i asked the same to you. Reference is taken from
Here
If the number of room members are limited (say max 5), you could design the table horizontally instead of vertically and artifically make it vertically again in a view.
Room_ID Room_Label
----------- --------------------------------------------------
3 Aconcagua
1 Kilimanjaro
2 Mount Everest
 
Member_ID Member_GivenName Member_LastName
----------- -------------------------------------------------- --------------------------------------------------
1 Alice Smith
2 Bob Taylor
3 Cynthia Miller
4 Dan Cooper
 
RoomMember_ID Room_ID Member1_ID Member2_ID Member3_ID Member4_ID Member5_ID
------------- ----------- ----------- ----------- ----------- ----------- -----------
1 1 1 2 3 NULL NULL
2 2 1 2 NULL NULL NULL
3 3 1 2 3 4 NULL
And the view could look like this:
Room_ID Member_ID
----------- -----------
1 1
1 2
1 3
2 1
2 2
3 1
3 2
3 3
3 4
Then the RoomMember table needs a unique constraint over the members
ALTER TABLE StackOverflow.RoomMember
ADD CONSTRAINT UK_RoomMember01
UNIQUE NONCLUSTERED (
Member1_ID ASC, Member2_ID ASC, Member3_ID ASC, Member4_ID ASC, Member5_ID ASC
)
and a check constraint that ensures the members can only be entered in ascending order from the left to the right with NULL values to the right:
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK
ADD CONSTRAINT [CK_RoomMembers]
CHECK ((([Member2_ID] IS NULL OR [Member2_ID]>[Member1_ID]) AND ([Member3_ID] IS NULL OR [Member2_ID] IS NOT NULL AND [Member3_ID]>[Member2_ID]) AND ([Member4_ID] IS NULL OR [Member3_ID] IS NOT NULL AND [Member4_ID]>[Member3_ID]) AND ([Member5_ID] IS NULL OR [Member4_ID] IS NOT NULL AND [Member5_ID]>[Member4_ID])))
And that is it. It's now not possible to enter the same combination of members of another room, and the view provides still access in better normalized fashion.
Full source code here:
CREATE TABLE [StackOverflow].[Member](
[Member_ID] [int] IDENTITY(1,1) NOT NULL,
[Member_GivenName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Member_LastName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_Member] PRIMARY KEY CLUSTERED
(
[Member_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
CREATE TABLE [StackOverflow].[Room](
[Room_ID] [int] IDENTITY(1,1) NOT NULL,
[Room_Label] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_Room] PRIMARY KEY CLUSTERED
(
[Room_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UK_Room] UNIQUE NONCLUSTERED
(
[Room_Label] 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
CREATE TABLE [StackOverflow].[RoomMember](
[RoomMember_ID] [int] IDENTITY(1,1) NOT NULL,
[Room_ID] [int] NOT NULL,
[Member1_ID] [int] NOT NULL,
[Member2_ID] [int] NULL,
[Member3_ID] [int] NULL,
[Member4_ID] [int] NULL,
[Member5_ID] [int] NULL,
CONSTRAINT [PK_RoomMember] PRIMARY KEY CLUSTERED
(
[RoomMember_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UK_RoomMember01] UNIQUE NONCLUSTERED
(
[Member1_ID] ASC,
[Member2_ID] ASC,
[Member3_ID] ASC,
[Member4_ID] ASC,
[Member5_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 [StackOverflow].[Member] ADD CONSTRAINT [DF_Member_Member_GivenName] DEFAULT (N'') FOR [Member_GivenName]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [FK_RoomMember_Member1] FOREIGN KEY([Member1_ID])
REFERENCES [StackOverflow].[Member] ([Member_ID])
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [FK_RoomMember_Member1]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [FK_RoomMember_Member2] FOREIGN KEY([Member2_ID])
REFERENCES [StackOverflow].[Member] ([Member_ID])
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [FK_RoomMember_Member2]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [FK_RoomMember_Member3] FOREIGN KEY([Member3_ID])
REFERENCES [StackOverflow].[Member] ([Member_ID])
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [FK_RoomMember_Member3]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [FK_RoomMember_Member4] FOREIGN KEY([Member4_ID])
REFERENCES [StackOverflow].[Member] ([Member_ID])
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [FK_RoomMember_Member4]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [FK_RoomMember_Member5] FOREIGN KEY([Member5_ID])
REFERENCES [StackOverflow].[Member] ([Member_ID])
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [FK_RoomMember_Member5]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [FK_RoomMember_Room] FOREIGN KEY([Room_ID])
REFERENCES [StackOverflow].[Room] ([Room_ID])
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [FK_RoomMember_Room]
GO
ALTER TABLE [StackOverflow].[RoomMember] WITH CHECK ADD CONSTRAINT [CK_RoomMembers] CHECK ((([Member2_ID] IS NULL OR [Member2_ID]>[Member1_ID]) AND ([Member3_ID] IS NULL OR [Member2_ID] IS NOT NULL AND [Member3_ID]>[Member2_ID]) AND ([Member4_ID] IS NULL OR [Member3_ID] IS NOT NULL AND [Member4_ID]>[Member3_ID]) AND ([Member5_ID] IS NULL OR [Member4_ID] IS NOT NULL AND [Member5_ID]>[Member4_ID])))
GO
ALTER TABLE [StackOverflow].[RoomMember] CHECK CONSTRAINT [CK_RoomMembers]
GO
CREATE VIEW [StackOverflow].[V_RoomMember]
AS
SELECT Room_ID, Member1_ID AS Member_ID FROM StackOverflow.RoomMember
UNION
SELECT Room_ID, Member2_ID AS Member_ID FROM StackOverflow.RoomMember WHERE Member2_ID IS NOT NULL
UNION
SELECT Room_ID, Member3_ID AS Member_ID FROM StackOverflow.RoomMember WHERE Member3_ID IS NOT NULL
UNION
SELECT Room_ID, Member4_ID AS Member_ID FROM StackOverflow.RoomMember WHERE Member4_ID IS NOT NULL
UNION
SELECT Room_ID, Member5_ID AS Member_ID FROM StackOverflow.RoomMember WHERE Member5_ID IS NOT NULL
GO
SET IDENTITY_INSERT [StackOverflow].[Room] ON
GO
INSERT [StackOverflow].[Room] ([Room_ID], [Room_Label]) VALUES (3, N'Aconcagua')
GO
INSERT [StackOverflow].[Room] ([Room_ID], [Room_Label]) VALUES (1, N'Kilimanjaro')
GO
INSERT [StackOverflow].[Room] ([Room_ID], [Room_Label]) VALUES (2, N'Mount Everest')
GO
SET IDENTITY_INSERT [StackOverflow].[Room] OFF
GO
SET IDENTITY_INSERT [StackOverflow].[Member] ON
GO
INSERT [StackOverflow].[Member] ([Member_ID], [Member_GivenName], [Member_LastName]) VALUES (1, N'Alice', N'Smith')
GO
INSERT [StackOverflow].[Member] ([Member_ID], [Member_GivenName], [Member_LastName]) VALUES (2, N'Bob', N'Taylor')
GO
INSERT [StackOverflow].[Member] ([Member_ID], [Member_GivenName], [Member_LastName]) VALUES (3, N'Cynthia', N'Miller')
GO
INSERT [StackOverflow].[Member] ([Member_ID], [Member_GivenName], [Member_LastName]) VALUES (4, N'Dan', N'Cooper')
GO
SET IDENTITY_INSERT [StackOverflow].[Member] OFF
GO
SET IDENTITY_INSERT [StackOverflow].[RoomMember] ON
GO
INSERT [StackOverflow].[RoomMember] ([RoomMember_ID], [Room_ID], [Member1_ID], [Member2_ID], [Member3_ID], [Member4_ID], [Member5_ID]) VALUES (1, 1, 1, 2, 3, NULL, NULL)
GO
INSERT [StackOverflow].[RoomMember] ([RoomMember_ID], [Room_ID], [Member1_ID], [Member2_ID], [Member3_ID], [Member4_ID], [Member5_ID]) VALUES (2, 2, 1, 2, NULL, NULL, NULL)
GO
INSERT [StackOverflow].[RoomMember] ([RoomMember_ID], [Room_ID], [Member1_ID], [Member2_ID], [Member3_ID], [Member4_ID], [Member5_ID]) VALUES (3, 3, 1, 2, 3, 4, NULL)
GO
SET IDENTITY_INSERT [StackOverflow].[RoomMember] OFF
GO

central attachment/file table design

UPDATE:
I have generated below tables from sql server.
here is the screen shots of my design:
shows the data after combining three tables, getting total of 12 rows
my request table has 4 rows and attachment table has 3 rows
CREATE TABLE [dbo].[attachment](
[attach_id] [int] IDENTITY(1,1) NOT NULL,
[process_type_id] [int] NULL,
[attach_content_type] [varchar](100) NULL,
[attach_name] [varchar](100) NULL,
CONSTRAINT [PK_attachment] PRIMARY KEY CLUSTERED
(
[attach_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]
CREATE TABLE [dbo].[process_type](
[process_type_id] [int] IDENTITY(1,1) NOT NULL,
[process_type] [varchar](100) NULL,
CONSTRAINT [PK_process_type] PRIMARY KEY CLUSTERED
(
[process_type_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]
CREATE TABLE [dbo].[request](
[request_Id] [int] IDENTITY(1,1) NOT NULL,
[request_desc] [varchar](200) NULL,
[process_type_id] [int] NOT NULL,
CONSTRAINT [PK_request] PRIMARY KEY CLUSTERED
(
[request_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]
CREATE TABLE [dbo].[request_review](
[review_request_Id] [int] IDENTITY(1,1) NOT NULL,
[review_desc] [varchar](200) NULL,
[process_type_id] [int] NULL,
CONSTRAINT [PK_request_review] PRIMARY KEY CLUSTERED
(
[review_request_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]
I am busy building a database, and now I have a question about my design.
I have got the following tables:
Customer
Employee
upload_doc
I want to be able to add multiple attachments to Customers, Employees
what is the best design:
design #1
Upload_doc
upload_doc_id (NOT auto generated)
upload_doc_name (uploaded doc name)
upload_content_type
upload_doc_data (blob)
employee
employee_id
first_name
middle_name
last_name
upload_doc_id
customer
customer_id
first_name
last_name
upload_doc_id
design #2
Upload_doc
upload_doc_id (AUTO generated)
upload_doc_name (uploaded doc name)
upload_content_type
upload_doc_data (blob)
employee_id
customer_id
employee
employee_id
first_name
middle_name
last_name
customer
customer_id
first_name
last_name
Design one, but would make upload_doc_id an auto gen id column.
If you are using MS SQL, I would use FILETABLE instead of blobs. Files in MS SQL
The info in your question is somewhat limited, but I'll give it a quick attempt. Personally I'd have a common table for personal information like: names and contact info.
Then have a type lookup table that defines what type of person/contact they are: customer / employee.
Then you can link docs to the common person table. Something like the below, which you can run as is:
CREATE TABLE #temp_person -- common information like name & contact info
(
PersonId INT ,
FirstName VARCHAR(20) ,
MiddleName VARCHAR(20) ,
LastName VARCHAR(20) ,
PersonTypeId INT -- lookup value to person type table
)
CREATE TABLE #temp_person_type -- determines if they are employees or customer
(
PersonTypeId INT ,
PersonType VARCHAR(10)
)
CREATE TABLE #temp_employee
(
EmployeeId INT ,
PersonId INT -- linked to person table
-- other fields would be employee specific
)
CREATE TABLE #temp_customer
(
CustomerId INT ,
PersonId INT -- linked to person table
-- other fields would be customer specific
)
CREATE TABLE #temp_upload_doc
(
UploadDocId INT ,
PersonId INT , -- linked to person table
DocName VARCHAR(20)
)
INSERT INTO #temp_person_type
( PersonTypeId, PersonType )
VALUES ( 1, 'Employee' ),
( 2, 'Customer' )
INSERT INTO #temp_person
( PersonId, FirstName, MiddleName, LastName, PersonTypeId )
VALUES ( 1, 'Bob', 'Jon', 'Smith', 1 ),
( 2, 'David', '', 'Jones', 1 ),
( 3, 'Andy', '', 'Johnson', 2 ),
( 4, 'Richard', '', 'Branson', 2 )
INSERT INTO #temp_customer
( CustomerId, PersonId )
VALUES ( 1, 3 ),
( 2, 4 )
INSERT INTO #temp_employee
( EmployeeId, PersonId )
VALUES ( 1, 1 ),
( 2, 2 )
INSERT INTO #temp_upload_doc
( UploadDocId, PersonId, DocName )
VALUES ( 1, 1, 'Doc 1' ),
( 2, 1, 'Doc 2' ),
( 3, 2, 'Doc blah' ),
( 4, 3, 'Doc dog' ),
( 5, 3, 'Doc images' ),
( 6, 4, 'Doc another' ),
( 7, 4, 'Doc la la la' )
-- EMPLOYEES AND DOCS
SELECT *
FROM #temp_person p
INNER JOIN #temp_person_type pt ON pt.PersonTypeId = p.PersonTypeId
INNER JOIN #temp_employee e ON e.PersonId = p.PersonId
INNER JOIN #temp_upload_doc u ON u.PersonId = e.PersonId
WHERE p.PersonTypeId = 1
-- CUSTOMERS AND DOCS
SELECT *
FROM #temp_person p
INNER JOIN #temp_person_type pt ON pt.PersonTypeId = p.PersonTypeId
INNER JOIN #temp_customer c ON c.PersonId = p.PersonId
INNER JOIN #temp_upload_doc u ON u.PersonId = c.PersonId
WHERE p.PersonTypeId = 2
DROP TABLE #temp_customer
DROP TABLE #temp_employee
DROP TABLE #temp_person
DROP TABLE #temp_upload_doc
DROP TABLE #temp_person_type

Resources