Nested SQL Queries 3 levels - sql

I am using MS Access and having troubles writing a query(s) to get my end result. Maybe someone can lend a hand.
I have Projects, Tasks and SubTasks tables. Each table has a related table for "Assignees". meaning a project could be assigned to an employee but the child tasks could be assigned to a different employee and still further the subtasks could then be assigned to other employees.
Now, when displaying this on screen, and I query for an employee that has been assigned to any project/Task/Subtask. I need that data to display but not other data. So for instance if the employee I query for only has been assigned to a task, then that project and task should display, but no additional projects/tasks/ and no subtasks. Likewise, if I query for an employee that only has been assigned to a subtask, then I only want to see the associated project and task. I think I can complete this with a series of queries...i think... but is there a slick method I can use to create this data.
Simply a select query with a series of joins could possibly work, but it doesnt because when an employee has been assigned to a subtask only and not to a project or task.
Thanks for any assistance!
Updated with additional information:
Table Structures:
CREATE TABLE [dbo].[Projects](
[ProjectID] [int] IDENTITY(1,1) NOT NULL,
[ProjectName] [varchar](100) NULL,
[ClientID] [int] NULL,
CREATE TABLE [dbo].[PM_ProjectAssignee](
[AssigneeID] [int] IDENTITY(1,1) NOT NULL,
[ProjectID] [int] NULL,
[EmployeeID] [int] NULL,
CREATE TABLE [dbo].[PM_ProjectTasks](
[ProjectTaskID] [int] IDENTITY(1,1) NOT NULL,
[ProjectID] [int] NULL,
[TaskID] [smallint] NULL,
CREATE TABLE [dbo].[PM_TaskAssignee](
[AssigneeID] [int] IDENTITY(1,1) NOT NULL,
[ProjectTaskID] [int] NULL,
[EmployeeID] [int] NULL,
CREATE TABLE [dbo].[PM_ProjectSubTasks](
[ProjectSubTaskID] [int] IDENTITY(1,1) NOT NULL,
[ProjectTaskID] [int] NULL,
[SubTaskDesc] [varchar](255) NULL,
CREATE TABLE [dbo].[PM_SubTaskAssignee](
[AssigneeID] [int] IDENTITY(1,1) NOT NULL,
[ProjectSubTaskID] [int] NULL,
[EmployeeID] [int] NULL,
With regards to queries I have tried...alot. I was implementing a scenario where I ended up with about a half dozen different queries all culminating into one (some of the queries where built with code to allow filtering) However the last one tried was:
SELECT ProjectID, ProjectName, EmployeeID, ProjectTaskID, EmployeeID, Association, ProjectSubTaskID, EmployeeID
FROM (qrTest3_Project LEFT JOIN qrTest2_Task ON qrTest3_Project.ProjectID = qrTest2_Task.ProjectID) LEFT JOIN qrtest1_SubTask ON qrTest2_Task.ProjectTaskID = qrtest1_SubTask.Association
WHERE (((qrTest3_Project.EmployeeID)=8)) OR (((qrTest2_Task.EmployeeID)=8)) OR (((qrtest1_SubTask.EmployeeID)=8));
the above query included other queries that simply joined each project/task/subtask to their respective assignee table. I can post those as well if needed.
I hope that provides the additional information you need? If not, happy to provide more.
Thanks!

I think I may have figured it out..as I sort of suspected, I was making it a bit more difficult then it needed to be. Simply joins really with criteria gives me the data I need and can work with.
SELECT PM_ProjectAssignee.ProjectID, PM_ProjectTasks.ProjectTaskID, PM_ProjectSubTasks.ProjectSubTaskID
FROM (((PM_ProjectAssignee
LEFT JOIN PM_ProjectTasks
ON PM_ProjectAssignee.ProjectID = PM_ProjectTasks.ProjectID)
LEFT JOIN PM_ProjectSubTasks
ON PM_ProjectTasks.ProjectTaskID = PM_ProjectSubTasks.ProjectTaskID)
LEFT JOIN PM_TaskAssignee
ON PM_ProjectTasks.ProjectTaskID = PM_TaskAssignee.ProjectTaskID)
LEFT JOIN PM_SubTaskAssignee
ON PM_ProjectSubTasks.ProjectSubTaskID = PM_SubTaskAssignee.ProjectSubTaskID
WHERE (((PM_ProjectAssignee.EmployeeID)=14))
OR (((PM_TaskAssignee.EmployeeID)=14))
OR (((PM_SubTaskAssignee.EmployeeID)=14))
GROUP BY PM_ProjectAssignee.ProjectID, PM_ProjectTasks.ProjectTaskID, PM_ProjectSubTasks.ProjectSubTaskID;

Related

How to setup trigger based audit? [duplicate]

This question already has answers here:
Log record changes in SQL server in an audit table
(7 answers)
Closed 2 years ago.
I have a table Employee:
CREATE TABLE [dbo].[Employee]
(
[EmployeeCode] [int] NOT NULL,
[FirstName] [varchar](50) NULL,
[LastName] [varchar](50) NULL,
[Email] [varchar](50) NULL,
[Position] [varchar](30) NULL
)
I want to log changes in Employee_Audit table every time there's a change in Position (along with the Old Position, New Position and Timestamp) in Employee table.
CREATE TABLE [dbo].[Employee_Audit]
(
[EmployeeCode] [int] NOT NULL,
[FirstName] [varchar](50) NULL,
[LastName] [varchar](50) NULL,
[Email] [varchar](50) NULL,
[PositionOld] [varchar](30) NULL,
[PositionNew] [varchar](30) NULL,
[Date] [datetime] NULL
)
How do I achieve this?
You basically need an UPDATE trigger that checks if the Position value has changed - and if so, records the details into Employee_Audit:
CREATE OR REPLACE trgEmployeeUpdate
ON dbo.Employee
AFTER UPDATE
AS
BEGIN
-- based on the Inserted and Deleted pseudo tables, join the rows
-- that were updated and look for changes in "Position"
INSERT INTO dbo.Employee_Audit (EmployeeCode, FirstName, LastName, Email,
PositionOld, PositionNew, [Date])
SELECT
i.EmployeeCode, i.FirstName, i.LastName, i.Email,
d.Position, i.Position, SYSDATETIME()
FROM
Inserted i
INNER JOIN
Deleted d ON i.EmployeeCode = d.EmployeeCode
WHERE
i.Position <> d.Position -- Position has changed
END
In addition to trigger option #marc_s mentioned, If you want to not just consider position, and considering all column changes auditing, below options provide you to do auditing, without any specific programming need. You can see whether it fits for your needs.
you can think of SQL Server Temporal Tables. Read on SQL Server Temporal Tables on MSDN. They provide transparent way to auditing the row changes.
You also have Change Data Capture option to track the historical changes for columns. Change Data Capture on MSDN

Implementing custom fields in a database for large numbers of records

I'm developing an app which requires a user defined custom fields on a contacts table. This contact table can contain many millions of contacts.
We're looking at using a secondary metadata table which stores information about the fields, along with a tertiary value table which stores the actual data.
Here's the rough schema:
CREATE TABLE [dbo].[Contact](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](max) NULL,
[MiddleName] [nvarchar](max) NULL,
[LastName] [nvarchar](max) NULL,
[Email] [nvarchar](max) NULL
)
CREATE TABLE [dbo].[CustomField](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FieldName] [nvarchar](50) NULL,
[Type] [varchar](50) NULL
)
CREATE TABLE [dbo].[ContactAndCustomField](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ContactID] [int] NULL,
[FieldID] [int] NULL,
[FieldValue] [nvarchar](max) NULL
)
However, this approach introduces a lot of complexity, particularly with regard to importing CSV files with multiple custom fields. At the moment this requires a update/join statement and a separate insert statement for every individual custom field. Joins would also be required to return custom field data for multiple rows at once
I've argued for this structure instead:
CREATE TABLE [dbo].[Contact](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FirstName] [nvarchar](max) NULL,
[MiddleName] [nvarchar](max) NULL,
[LastName] [nvarchar](max) NULL,
[Email] [nvarchar](max) NULL
[CustomField1] [nvarchar](max) NULL
[CustomField2] [nvarchar](max) NULL
[CustomField3] [nvarchar](max) NULL /* etc, adding lots of empty fields */
)
CREATE TABLE [dbo].[ContactCustomField](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FieldIndex] [int] NULL,
[FieldName] [nvarchar](50) NULL,
[Type] [varchar](50) NULL
)
The downside of this second approach is that there is a finite number of custom fields that must be specified when the contacts table is created. I don't think that's a major hurdle given the performance benefits it will surely have when importing large CSV files, and returning result sets.
What approach is the most efficient for large numbers of rows? Are there any downsides to the second technique that I'm not seeing?
Microsoft introduced sparse columns exactly for this type of problems. Tha point is that in a "classic" design you end up with large number of columns, most of the NULLs for any particular row. Same here with sparse columns, but NULLs don't require any storage. Moreover, you can create sets of columns and modify sets with XML.
Performance- and storage-wise, sparse columns are the winner.
http://technet.microsoft.com/en-us/library/cc280604.aspx
uery performance. Query performance for any "property bag table" approach is funny and comically slow - but if you need flexibility you can either have a dynamic table that is changed via an editor OR you have a property bag table. So when you need it, you need it.
But expect the performance to be slow.
The best approach would likely be a ContactCustomFields table which has - fields that are determined by an editor.

Create table with sum of several conditions from other table

I have another problem, as I need to have a sum in a table based on several data from other table (COST). Solution above brings data on one condition, what I need is to have sum on several conditions from other table:
So I have Cost table, which looks:
CREATE TABLE [dbo].[Cost](
[ID_Cost] [int] NOT NULL,
[Name] [varchar](50) NULL,
[ID_CostCategory] [int] NULL,
[ID_Department] [int] NULL,
[ID_Project] [int] NULL,
[Value] [money] NULL,
) go
then I have Department table, with colums: ID_Department, Name, Plan,
What I want to do is to make in Department table, column Realization which sum values from Cost table based on several conditions (ID_CostCategory and ID_Department and if possible ID_Project)
So in result I get in Department table, column Realization with sum of cost from Cost table per ID_CostCategory and ID_Department.

SQL Historical Changes

I have been trying to wrap my head around this for some time now and just can't seem to find a good solution so I am consulting the overflow. I have a table which looks a little like this:
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](255) NOT NULL,
[Title] [varchar](255) NULL,
[QueueId] [int] NOT NULL,
[SupervisorId] [int] NULL,
Employees are moved from one queue to another queue at different time intervals. how should I structure my second table so I can see not only how many people where in a queue at a specific time interval but also who they were?
I would say the table will look like this:
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[QueueId] [int] NOT NULL,
[Start] [datetime] NOT NULL,
[End] [datetime] NOT NULL
The unfortunate thing is you have to go back and "end date" the prior row. If I am the one doing it, I will skip the [End] and create a view on top of the table that will supply the [End].
The view will look like
SELECT A.[EmployeeId]
, A.[QueueId]
, A.[Start]
, COALESCE(MIN([B.Start]),'9999-12-31') as [END]
FROM Table A
LEFT OUTER JOIN Table B
ON A.[EmployeeId] = B.[EmployeeId]
AND A.[Start] < B.[Start]
If you do it this way, you cannot use BETWEEN when joining to this view. You have to say >= [Start] and < [END]. Anyway, it's safer and more robust since you don't have to decide on a date/time "rounding" unit.
queueid int
status varchar(20)
start datetime
end datetime
Your 2nd table should have a primary key, datetime, and count columns. However, you will need a 3rd table that lists the people in the queue, since the count & list reside in different hierarchical levels.

Get value from other foreign key table based on current table value

I am working on a project where I need to extract the data from excel sheet to SQL Server
, well that bit have done successfully. Now my problem is that for a particular column
called product size, I want to update current table based on product size in other table, I am really very confused , please help me out
Please find the table structure
CREATE TABLE [dbo].[T_Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[PartNo] [nvarchar](255) NULL,
[CategoryID] [int] NULL,
[MaterialID] [float] NULL,
[WireformID] [float] NULL,
[ProductName] [nvarchar](50) NULL,
[ProductSize] [nvarchar](50) NULL,
[ProductLength] [varchar](20) NULL,
[ProductActive] [bit] NULL,
[ProductImage] [varchar](60) NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[T_ProductSize](
[Code] [int] IDENTITY(1,1) NOT NULL,
[ProductSize] [nvarchar](50) NULL,
[Length] [nchar](20) NULL
) ON [PRIMARY]
GO
OK, so ignore the previous answer, I got the wrong end of the stick!!
You want something like this I think:
UPDATE T_Product
SET [ProductLength] = ps.[Length]
FROM T_Product p
INNER JOIN T_ProductSize ps
ON p.[ProductSize] = ps.[ProductSize]
That will take the Length value from T_ProductSize and place it in T_Product.ProductLength based on the value of T_Product.ProductSize
You mention a foreign key but you haven't included a definition for it. Is it between the two tables in your example? If so, which columns make the key? Is product size the key? If so, then your question doesn't make a lot of sense as the value will be the same in both tables.
Is it possible that you mean the product size is to be stored in a separate table and not in the T_Product table? In that case then instead of ProductSize in T_Product you will want the code from the T_ProductSize table (can I also suggest that instead of 'code' you call it 'ProductSizeCode' or better yet 'ProductSizeId' or similar? having columns simply called code can be very confusing as you have no simple way of know what table that value is in). Also, you should always create a primary key on each table: You cannot have a foreign key without one. They don't have to be clustered, that will depend upon hwo your search the table, but I am using a clustered PK for this example. That would give you something like this:
CREATE TABLE [dbo].[T_Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[PartNo] [nvarchar](255) NULL,
[CategoryID] [int] NULL,
[MaterialID] [float] NULL,
[WireformID] [float] NULL,
[ProductName] [nvarchar](50) NULL,
[ProductSizeId] [int] NOT NULL,
[ProductLength] [varchar](20) NULL,
[ProductActive] [bit] NULL,
[ProductImage] [varchar](60) NULL
CONSTRAINT [PK_T_Product] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[T_ProductSize](
[ProductSizeId] [int] IDENTITY(1,1) NOT NULL,
[ProductSize] [nvarchar](50) NULL,
[Length] [nchar](20) NULL
CONSTRAINT [PK_T_ProductSize] PRIMARY KEY CLUSTERED
(
[ProductSizeId] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
--Now add your foreign key to T_Product.
ALTER TABLE [T_Product] WITH NOCHECK ADD CONSTRAINT [FK_Product_ProductSize] FOREIGN KEY([ProductSizeId])
REFERENCES [T_ProductSize] ([ProductSizeId])
GO
ALTER TABLE [T_Product] CHECK CONSTRAINT [FK_Product_ProductSize]
GO
Now, to retrieve your product along with the product size use something like this:
SELECT p.[ProductID], p.[PartNo], p.[CategoryID], p.[MaterialID], p.[WireformID], p.[ProductName],
ps.[ProductSize], ps.[Length], p.[ProductLength], p.[ProductActive], p.[ProductImage]
FROM [T_Product] p
INNER JOIN [T_ProductSize] ps
ON ps.[ProductSizeId] = p.[ProductSizeId]
If I have understood you correctly, then this is what I think you're after. If not, then have another go at explaining what it is you need and I'll try again.
Try this...
UPDATE t2
SET t2.ProductLength = t1.Length
FROM dbo.T_ProductSize t1
INNER JOIN dbo.T_Product t2 ON t1.ProductSize = t2.ProductSize