views:

95

answers:

5

So I have a table that looks like this:

ProjectID    TaskID     Date
000          001        10/28/09
000          002        12/1/09
000          003        02/24/10
001          001        04/14/10
001          002        07/5/10
001          003        02/24/11
002          001        06/07/10
002          002        07/7/10
002          003        09/13/12

Assume there are many projects and many tasks, but each project contains the same tasks. I want to copy dates in the following manner:

One project (000) has the master dates. I want to copy those dates for each task to several other projects (001, 002 in the example data).

So, if task 001 in project 000 has a date of 10/28/09, I want task 001 in other projects (I know their IDs) to have the same date.

If task 002 in project 001 has date 12/1/09, I want task 002 to have this date in each of the other projects as well.

Is there one query that can do this? I think there should be, but I can't figure it out right now.

BTW I am using SqlServer 2005.

A: 
UPDATE dbo.Projects
SET Date = (SELECT Date FROM dbo.Projects p1
            WHERE p1.ProjectID = '000' AND p1.TaskID = dbo.Projects.TaskID)
WHERE ProjectID IN ('P01', 'P02', 'P03', 'P04')
AND TaskID IN ('001', '002', '003')

Would that do it for you?

So for TaskID = 001, this statement will

 SELECT Date FROM dbo.Projects WHERE ProjectID = '000' AND TaskID = '001'

and then update each of the projects (P01-P04) and TaskID=001 to this date. That's what you're looking for, no??

You can also use an OUTPUT clause to PROVE to you what is being updated:

UPDATE dbo.Projects
SET Date = (SELECT Date FROM dbo.Projects p1
            WHERE p1.ProjectID = '000' AND p1.TaskID = dbo.Projects.TaskID)
OUTPUT inserted.ProjectID, inserted.TaskID, inserted.Date
WHERE ProjectID IN ('P01', 'P02', 'P03', 'P04')
AND TaskID IN ('001', '002', '003')

This will cause each row being updated to output the new values (e.g. after the update) so you can check and see what gets updated, and to what values.

Just ran the query and this is the results I get:

ProjectID   TaskID Date
   0       1 2009-10-28 00:00:00.000
   0       2 2009-12-01 00:00:00.000
   0       3 2010-02-24 00:00:00.000
   1       1 2009-10-28 00:00:00.000
   1       2 2009-12-01 00:00:00.000
   1       3 2010-02-24 00:00:00.000
   2       1 2009-10-28 00:00:00.000
   2       2 2009-12-01 00:00:00.000
   2       3 2010-02-24 00:00:00.000

The dates for Projects 1 and 2 and Tasks 1,2,3 have been set to the values of the "master" project 0.

marc_s
On first glance, it does not seem that this query matches the dates from the master to the others for each task. Am I reading it incorrectly?
Matthew Jones
It selects the "Date" from the project "000" for each TaskID that you're dealing with, and sets the "Date" for the other projects to that selected date
marc_s
Whoever voted you down is smoking something, this worked and had a great explanation. Thanks a bunch!
Matthew Jones
@Matthew: yes, i was wondering about that downvote too...... anyway......
marc_s
You got down voted because performing the additional SELECT in the SET list causes unnecessary Scalar Compute and a Top steps in the Execution Plan where as using a JOIN does not.
CptSkippy
@CptSkippy: thanks for explaining your motivation. OK, agreed - it's not absolutely necessary and could be done another way. On this scale, however - three projects and three tasks - I doubt it really even makes a measurable difference.....
marc_s
On the scale of the sample data there isn't but we don't know what the size of his dataset really is. I also happen to think that the SELECT in the SET list is ugly, and difficult to read and maintain compared to a JOIN. If you look at the execution plan, it's compiled down to almost the same JOIN, albeit with Scalar Compute and Top steps.
CptSkippy
A: 

Perhaps something like this:

INSERT INTO Projects(ProjectID, TaskID, Date)
SELECT P2.ProjectId, P1.TaskID, P1.Date
FROM Projects P1
CROSS JOIN (SELECT DISTINCT ProjectID FROM Projects WHERE ProjectId <> '000') P2

I'm not sure which database engine you are using, and some may allow for a more natural syntax than the above.

The above also obviously assumes that the timeslots haven't already been set for the other projects and that you're trying to define new timeslots instead of updating existing ones.

David Andres
A: 

This should work just fine:

UPDATE projects SET [date] = (SELECT [date] FROM projects p1 WHERE project = '000' AND p1.task = projects.task)
Lukasz Lysik
A: 

This is what you want, just replace "..." with the CSV list of projects.

UPDATE c
SET c.Date = p.Date
FROM Projects AS [c]
JOIN Projects AS [p]
    ON p.TaskID = c.TaskID
    AND p.ProjectID = '000'
WHERE c.ProjectID IN (...)
CptSkippy
A: 
DECLARE @MasterProjectId varchar(10)
DECLARE @ChildProjectIds varchar(100)

Select 
@MasterProjectId = '000',
@ChildProjectIds = '''123'',''456'''


EXECUTE sp_executesql N'Update childProjects
Set childProjects.[Date]= masterProject.[Date]
from Projects masterProject
Inner join Projects childProjects on childProjects.TaskId = masterProject.TaskId and childProjects.ProjectId in (' + @ChildProjectIds + ')
where masterProject.ProjectId = ' + @MasterProjectId
ttomsen
there's really no need to create a dynamic SQL statement and execute it - seems overly complicated, IMO
marc_s
to format your code nicely, you should highlight your lines of code and then press the "code" button (010 101) on the toolbar - makes a world of difference!
marc_s