sql server programming:
hey all, Table1 empId,fname,lname 1,john,smith Table2 empId,date,salary 1,1/1/2005,$25 1,1/1/2006,$50 Table3 empId,startDate, endDate, jobPosition 1,1/1/2005,6/1/2005,director 1,6/2/2005,12/31/2005,executive 1/1/2006,null,ceo i'd like to have a report like the following: empID,fname + lname, current salary, current position could this be done in one uncomplicated sql statement? thanks,
yes, that's correct. [quoted text, click to view] "Mike Walsh" wrote: > okay.. so I actually totally missed the empID field, on my quick read I saw > it as part of a date and presumed we were talking about different employees. > > For this report you actually just want the current salary and the current > position I presume? > >
[quoted text, click to view] > could this be done in one uncomplicated sql statement?
It depends what you mean by uncomplicated. The method below uses derived tables: CREATE TABLE dbo.Table1 ( empId int NOT NULL CONSTRAINT PK_Table1 PRIMARY KEY, fname varchar(30) NOT NULL, lname varchar(30) NOT NULL ) GO INSERT INTO dbo.Table1 SELECT 1,'john','smith' GO CREATE TABLE dbo.Table2 ( empId int NOT NULL, effective_date datetime NOT NULL, salary money NOT NULL, CONSTRAINT PK_Table2 PRIMARY KEY ( empId, effective_date ) ) GO INSERT INTO dbo.Table2 SELECT 1, '20050101', $25 UNION ALL SELECT 1, '20060101', $50 GO CREATE TABLE dbo.Table3 ( empId int NOT NULL, start_date datetime NOT NULL, end_date datetime NULL, jobPosition varchar(30) NOT NULL, CONSTRAINT PK_Table3 PRIMARY KEY ( empId, start_date ) ) INSERT INTO dbo.Table3 SELECT 1, '20050101', '20050601', 'director' UNION ALL SELECT 1, '20050602', '20051231', 'executive' UNION ALL SELECT 1, '20060101', NULL, 'ceo' GO SELECT t1.empId, t1.fname + ' ' + t1.lname AS FullName, t2.CurrentSalary, t3.CurrentPosition FROM dbo.Table1 AS t1 JOIN (SELECT empId, salary AS CurrentSalary FROM dbo.Table2 AS t2 WHERE effective_date = ( SELECT MAX(effective_date) FROM dbo.Table2 AS latest_t2 WHERE latest_t2.empId = t2.empId) ) AS t2 ON t2.empId = t1.empId JOIN (SELECT empId, jobPosition AS CurrentPosition FROM dbo.Table3 AS t3 WHERE start_date = ( SELECT MAX(start_date) FROM dbo.Table3 AS latest_t3 WHERE latest_t3.empId = t3.empId) ) AS t3 ON t3.empId = t1.empId -- Hope this helps. Dan Guzman SQL Server MVP [quoted text, click to view] "rodchar" <rodchar@discussions.microsoft.com> wrote in message news:F69F9D81-8972-42C5-91A5-25295F62BA15@microsoft.com... > hey all, > > Table1 > empId,fname,lname > 1,john,smith > > Table2 > empId,date,salary > 1,1/1/2005,$25 > 1,1/1/2006,$50 > Table3 > empId,startDate, endDate, jobPosition > 1,1/1/2005,6/1/2005,director > 1,6/2/2005,12/31/2005,executive > 1/1/2006,null,ceo > > i'd like to have a report like the following: > empID,fname + lname, current salary, current position > > could this be done in one uncomplicated sql statement? > > thanks, > rodchar
Yes.. SELECT T1.empID, T1.fname + ' ' + T1.lname as FullName, t2.salary, t2.jobPosition FROM Table1 AS T1 INNER JOIN Table2 AS T2 ON T1.empID = T2.empID [quoted text, click to view] "rodchar" <rodchar@discussions.microsoft.com> wrote in message news:F69F9D81-8972-42C5-91A5-25295F62BA15@microsoft.com... > hey all, > > Table1 > empId,fname,lname > 1,john,smith > > Table2 > empId,date,salary > 1,1/1/2005,$25 > 1,1/1/2006,$50 > Table3 > empId,startDate, endDate, jobPosition > 1,1/1/2005,6/1/2005,director > 1,6/2/2005,12/31/2005,executive > 1/1/2006,null,ceo > > i'd like to have a report like the following: > empID,fname + lname, current salary, current position > > could this be done in one uncomplicated sql statement? > > thanks, > rodchar
Sorry I forgot Table3 when looking through your example. Same concept just introduce another table to the join. SELECT T1.empID, T1.fname + ' ' + T1.lname as FullName, t2.salary, t3.jobPosition FROM Table1 AS T1 INNER JOIN Table2 AS T2 ON T1.empID = T2.empID INNER JOIN Table3 AS T3 ON T1.EmpID = T3.empID [quoted text, click to view] "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message news:ON8VW2ynHHA.4552@TK2MSFTNGP04.phx.gbl... > Yes.. > > SELECT T1.empID, T1.fname + ' ' + T1.lname as FullName, t2.salary, > t2.jobPosition > FROM Table1 AS T1 > INNER JOIN Table2 AS T2 > ON T1.empID = T2.empID > > > "rodchar" <rodchar@discussions.microsoft.com> wrote in message > news:F69F9D81-8972-42C5-91A5-25295F62BA15@microsoft.com... >> hey all, >> >> Table1 >> empId,fname,lname >> 1,john,smith >> >> Table2 >> empId,date,salary >> 1,1/1/2005,$25 >> 1,1/1/2006,$50 >> Table3 >> empId,startDate, endDate, jobPosition >> 1,1/1/2005,6/1/2005,director >> 1,6/2/2005,12/31/2005,executive >> 1/1/2006,null,ceo >> >> i'd like to have a report like the following: >> empID,fname + lname, current salary, current position >> >> could this be done in one uncomplicated sql statement? >> >> thanks, >> rodchar > >
okay.. so I actually totally missed the empID field, on my quick read I saw it as part of a date and presumed we were talking about different employees. For this report you actually just want the current salary and the current position I presume?
[quoted text, click to view] > Dan if you have a few moments could you compare them and help me wrap my > head around them? I am going to look at the query plans in more detail > when I have more time later but any thoughts help :)
I loaded 1M, 2M and 3M rows into Table1, Table2 and Table3 respectively using the script below. When I examined the execution plans of both queries in a single batch, mine showed a relative cost of 43% vs. 57% for yours. However, when I removed the extraneous GROUP BY from your query, the costs and plans were identical. I guess the optimizer did it's job ;-) Since rodchar didn't provide the actual schema (including indexes), we can only guess what performance might be the the actual environment. TRUNCATE TABLE dbo.Table1 TRUNCATE TABLE dbo.Table2 TRUNCATE TABLE dbo.Table3 INSERT INTO dbo.Table1 SELECT Nums.ID, 'john', 'smith' FROM ( SELECT Num1.Num + 1 + (Num2.Num * 10) + (Num3.Num * 100) + (Num4.Num * 1000) + (Num5.Num * 10000) + (Num6.Num * 100000) AS ID FROM ( SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS Num1 CROSS JOIN ( SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS Num2 CROSS JOIN ( SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS Num3 CROSS JOIN ( SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS Num4 CROSS JOIN ( SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS Num5 CROSS JOIN ( SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS Num6 ) AS Nums INSERT INTO dbo.Table2 SELECT empId, '20050101', $25 FROM dbo.Table1 UNION ALL SELECT empId, '20060101', $50 FROM dbo.Table1 INSERT INTO dbo.Table3 SELECT empId, '20050101', '20050601', 'director' FROM dbo.Table1 UNION ALL SELECT empId, '20050602', '20051231', 'executive' FROM dbo.Table1 UNION ALL SELECT empId, '20060101', NULL, 'ceo' FROM dbo.Table1 UPDATE STATISTICS dbo.Table1 UPDATE STATISTICS dbo.Table2 UPDATE STATISTICS dbo.Table3 GO -- Hope this helps. Dan Guzman SQL Server MVP [quoted text, click to view] "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message news:eSDkYVznHHA.5032@TK2MSFTNGP02.phx.gbl... > Which actually brings up a question in my mind. Why does the version I > wrote perform better? I would actually though Dan's would have from past > experience with complex join conditions (like on involving an = comparison > to a subquery). > > Dan if you have a few moments could you compare them and help me wrap my > head around them? I am going to look at the query plans in more detail > when I have more time later but any thoughts help :) > > Here is my version which should work with your DDL, Dan. > > select t1.empID, t1.fname + ' ' + t1.lname, tt2.salary , tt3.jobposition > > from table1 as t1 > > inner join table2 tt2 > > on t1.empid = tt2.empid > > and tt2.effective_date = (select max(table2.effective_date) from Table2 > > where table2.empId = tt2.empid > > group by table2.empid) > > inner join table3 tt3 > > on t1.empid = tt3.empid > > and tt3.start_date = (select max(table3.start_date) from table3 > > where table3.empid = tt3.empid) > > "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message > news:OeodYRznHHA.4192@TK2MSFTNGP06.phx.gbl... >> Or Dan's solution also works :) >> >> They should both give you what you are looking for. I think Dan's is >> prettier with using the derived table rather than using correlated >> subqueries as I did in the join's ON clause. I just ran Dan's create >> table scripts and compared the two. They both gave the same results with >> close performance. The one I posted performed a bit better but this is >> not a real world test with such small tables and I am not sure which >> would perform better for a large table. >> >> "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message >> news:F5902945-7587-4FBC-B176-6C8CBB8187F1@microsoft.com... >>>> could this be done in one uncomplicated sql statement? >>> >>> It depends what you mean by uncomplicated. The method below uses >>> derived tables: >>> >>> CREATE TABLE dbo.Table1 >>> ( >>> empId int NOT NULL >>> CONSTRAINT PK_Table1 PRIMARY KEY, >>> fname varchar(30) NOT NULL, >>> lname varchar(30) NOT NULL >>> ) >>> GO >>> >>> INSERT INTO dbo.Table1 >>> SELECT 1,'john','smith' >>> GO >>> >>> CREATE TABLE dbo.Table2 >>> ( >>> empId int NOT NULL, >>> effective_date datetime NOT NULL, >>> salary money NOT NULL, >>> CONSTRAINT PK_Table2 PRIMARY KEY >>> ( >>> empId, >>> effective_date >>> ) >>> ) >>> GO >>> >>> INSERT INTO dbo.Table2 >>> SELECT 1, '20050101', $25 >>> UNION ALL SELECT 1, '20060101', $50 >>> GO >>> >>> CREATE TABLE dbo.Table3 >>> ( >>> empId int NOT NULL, >>> start_date datetime NOT NULL, >>> end_date datetime NULL, >>> jobPosition varchar(30) NOT NULL, >>> CONSTRAINT PK_Table3 PRIMARY KEY >>> ( >>> empId, >>> start_date >>> ) >>> ) >>> >>> INSERT INTO dbo.Table3 >>> SELECT 1, '20050101', '20050601', 'director' >>> UNION ALL SELECT 1, '20050602', '20051231', 'executive' >>> UNION ALL SELECT 1, '20060101', NULL, 'ceo' >>> GO >>> >>> SELECT >>> t1.empId, >>> t1.fname + ' ' + t1.lname AS FullName, >>> t2.CurrentSalary, >>> t3.CurrentPosition >>> FROM dbo.Table1 AS t1 >>> JOIN (SELECT empId, salary AS CurrentSalary >>> FROM dbo.Table2 AS t2 >>> WHERE effective_date = ( >>> SELECT MAX(effective_date) >>> FROM dbo.Table2 AS latest_t2 >>> WHERE latest_t2.empId = t2.empId) >>> ) AS t2 ON t2.empId = t1.empId >>> JOIN (SELECT empId, jobPosition AS CurrentPosition >>> FROM dbo.Table3 AS t3 >>> WHERE start_date = ( >>> SELECT MAX(start_date) >>> FROM dbo.Table3 AS latest_t3 >>> WHERE latest_t3.empId = t3.empId) >>> ) AS t3 ON t3.empId = t1.empId >>>
alright so something like this should work for you: select t1.emp_ID, t1.fname + ' ' + t1.last_name, tt2.salary , tt3.jobposition from table1 as t1 inner join table2 tt2 on t1.emp_id = tt2.emp_id and tt2.[date] = (select max(table2.[date]) from Table2 where table2.emp_Id = tt2.emp_id group by table2.emp_id) inner join table3 tt3 on t1.emp_id = tt3.emp_id and tt3.start_date = (select max(table3.start_date) from table3 where table3.emp_id = tt3.emp_id) Not as simple as what I first posted but that was because I had a simple lack of understanding of your issue :) [quoted text, click to view] "rodchar" <rodchar@discussions.microsoft.com> wrote in message news:DB3A3766-8A1D-4CF7-BABC-1665E70ABB80@microsoft.com... > yes, that's correct. > > "Mike Walsh" wrote: > >> okay.. so I actually totally missed the empID field, on my quick read I >> saw >> it as part of a date and presumed we were talking about different >> employees. >> >> For this report you actually just want the current salary and the current >> position I presume? >> >> >>
Or Dan's solution also works :) They should both give you what you are looking for. I think Dan's is prettier with using the derived table rather than using correlated subqueries as I did in the join's ON clause. I just ran Dan's create table scripts and compared the two. They both gave the same results with close performance. The one I posted performed a bit better but this is not a real world test with such small tables and I am not sure which would perform better for a large table. [quoted text, click to view] "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message news:F5902945-7587-4FBC-B176-6C8CBB8187F1@microsoft.com... >> could this be done in one uncomplicated sql statement? > > It depends what you mean by uncomplicated. The method below uses derived > tables: > > CREATE TABLE dbo.Table1 > ( > empId int NOT NULL > CONSTRAINT PK_Table1 PRIMARY KEY, > fname varchar(30) NOT NULL, > lname varchar(30) NOT NULL > ) > GO > > INSERT INTO dbo.Table1 > SELECT 1,'john','smith' > GO > > CREATE TABLE dbo.Table2 > ( > empId int NOT NULL, > effective_date datetime NOT NULL, > salary money NOT NULL, > CONSTRAINT PK_Table2 PRIMARY KEY > ( > empId, > effective_date > ) > ) > GO > > INSERT INTO dbo.Table2 > SELECT 1, '20050101', $25 > UNION ALL SELECT 1, '20060101', $50 > GO > > CREATE TABLE dbo.Table3 > ( > empId int NOT NULL, > start_date datetime NOT NULL, > end_date datetime NULL, > jobPosition varchar(30) NOT NULL, > CONSTRAINT PK_Table3 PRIMARY KEY > ( > empId, > start_date > ) > ) > > INSERT INTO dbo.Table3 > SELECT 1, '20050101', '20050601', 'director' > UNION ALL SELECT 1, '20050602', '20051231', 'executive' > UNION ALL SELECT 1, '20060101', NULL, 'ceo' > GO > > SELECT > t1.empId, > t1.fname + ' ' + t1.lname AS FullName, > t2.CurrentSalary, > t3.CurrentPosition > FROM dbo.Table1 AS t1 > JOIN (SELECT empId, salary AS CurrentSalary > FROM dbo.Table2 AS t2 > WHERE effective_date = ( > SELECT MAX(effective_date) > FROM dbo.Table2 AS latest_t2 > WHERE latest_t2.empId = t2.empId) > ) AS t2 ON t2.empId = t1.empId > JOIN (SELECT empId, jobPosition AS CurrentPosition > FROM dbo.Table3 AS t3 > WHERE start_date = ( > SELECT MAX(start_date) > FROM dbo.Table3 AS latest_t3 > WHERE latest_t3.empId = t3.empId) > ) AS t3 ON t3.empId = t1.empId > > -- > Hope this helps. > > Dan Guzman > SQL Server MVP > > "rodchar" <rodchar@discussions.microsoft.com> wrote in message > news:F69F9D81-8972-42C5-91A5-25295F62BA15@microsoft.com... >> hey all, >> >> Table1 >> empId,fname,lname >> 1,john,smith >> >> Table2 >> empId,date,salary >> 1,1/1/2005,$25 >> 1,1/1/2006,$50 >> Table3 >> empId,startDate, endDate, jobPosition >> 1,1/1/2005,6/1/2005,director >> 1,6/2/2005,12/31/2005,executive >> 1/1/2006,null,ceo >> >> i'd like to have a report like the following: >> empID,fname + lname, current salary, current position >> >> could this be done in one uncomplicated sql statement? >> >> thanks, >> rodchar >
[quoted text, click to view] Which actually brings up a question in my mind. Why does the version I wrote
perform better? I would actually though Dan's would have from past experience with complex join conditions (like on involving an = comparison to a subquery). Dan if you have a few moments could you compare them and help me wrap my head around them? I am going to look at the query plans in more detail when I have more time later but any thoughts help :) Here is my version which should work with your DDL, Dan. select t1.empID, t1.fname + ' ' + t1.lname, tt2.salary , tt3.jobposition from table1 as t1 inner join table2 tt2 on t1.empid = tt2.empid and tt2.effective_date = (select max(table2.effective_date) from Table2 where table2.empId = tt2.empid group by table2.empid) inner join table3 tt3 on t1.empid = tt3.empid and tt3.start_date = (select max(table3.start_date) from table3 where table3.empid = tt3.empid) [quoted text, click to view] "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message news:OeodYRznHHA.4192@TK2MSFTNGP06.phx.gbl... > Or Dan's solution also works :) > > They should both give you what you are looking for. I think Dan's is > prettier with using the derived table rather than using correlated > subqueries as I did in the join's ON clause. I just ran Dan's create table > scripts and compared the two. They both gave the same results with close > performance. The one I posted performed a bit better but this is not a > real world test with such small tables and I am not sure which would > perform better for a large table. > > "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message > news:F5902945-7587-4FBC-B176-6C8CBB8187F1@microsoft.com... >>> could this be done in one uncomplicated sql statement? >> >> It depends what you mean by uncomplicated. The method below uses derived >> tables: >> >> CREATE TABLE dbo.Table1 >> ( >> empId int NOT NULL >> CONSTRAINT PK_Table1 PRIMARY KEY, >> fname varchar(30) NOT NULL, >> lname varchar(30) NOT NULL >> ) >> GO >> >> INSERT INTO dbo.Table1 >> SELECT 1,'john','smith' >> GO >> >> CREATE TABLE dbo.Table2 >> ( >> empId int NOT NULL, >> effective_date datetime NOT NULL, >> salary money NOT NULL, >> CONSTRAINT PK_Table2 PRIMARY KEY >> ( >> empId, >> effective_date >> ) >> ) >> GO >> >> INSERT INTO dbo.Table2 >> SELECT 1, '20050101', $25 >> UNION ALL SELECT 1, '20060101', $50 >> GO >> >> CREATE TABLE dbo.Table3 >> ( >> empId int NOT NULL, >> start_date datetime NOT NULL, >> end_date datetime NULL, >> jobPosition varchar(30) NOT NULL, >> CONSTRAINT PK_Table3 PRIMARY KEY >> ( >> empId, >> start_date >> ) >> ) >> >> INSERT INTO dbo.Table3 >> SELECT 1, '20050101', '20050601', 'director' >> UNION ALL SELECT 1, '20050602', '20051231', 'executive' >> UNION ALL SELECT 1, '20060101', NULL, 'ceo' >> GO >> >> SELECT >> t1.empId, >> t1.fname + ' ' + t1.lname AS FullName, >> t2.CurrentSalary, >> t3.CurrentPosition >> FROM dbo.Table1 AS t1 >> JOIN (SELECT empId, salary AS CurrentSalary >> FROM dbo.Table2 AS t2 >> WHERE effective_date = ( >> SELECT MAX(effective_date) >> FROM dbo.Table2 AS latest_t2 >> WHERE latest_t2.empId = t2.empId) >> ) AS t2 ON t2.empId = t1.empId >> JOIN (SELECT empId, jobPosition AS CurrentPosition >> FROM dbo.Table3 AS t3 >> WHERE start_date = ( >> SELECT MAX(start_date) >> FROM dbo.Table3 AS latest_t3 >> WHERE latest_t3.empId = t3.empId) >> ) AS t3 ON t3.empId = t1.empId >> >> -- >> Hope this helps. >> >> Dan Guzman >> SQL Server MVP >> >> "rodchar" <rodchar@discussions.microsoft.com> wrote in message >> news:F69F9D81-8972-42C5-91A5-25295F62BA15@microsoft.com... >>> hey all, >>> >>> Table1 >>> empId,fname,lname >>> 1,john,smith >>> >>> Table2 >>> empId,date,salary >>> 1,1/1/2005,$25 >>> 1,1/1/2006,$50 >>> Table3 >>> empId,startDate, endDate, jobPosition >>> 1,1/1/2005,6/1/2005,director >>> 1,6/2/2005,12/31/2005,executive >>> 1/1/2006,null,ceo >>> >>> i'd like to have a report like the following: >>> empID,fname + lname, current salary, current position >>> >>> could this be done in one uncomplicated sql statement? >>> >>> thanks, >>> rodchar >> > >
thanks. That was strange. I was getting 43 for mine and 57 for yours. (without inserting the higher sample data). I took out the group by you pointed out :) (I was going down a different path first and left that) and then each query was good at 50%.. But on your machine with my oops group by your plan had the 43 and mine had the 57 (percent of total relative cost) mirror plans. I guess my machine favors me <eg> Thanks for your time. [quoted text, click to view] "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message news:1F16EFCF-E5BB-45FA-9C76-7C7CC7CE3305@microsoft.com... >> Dan if you have a few moments could you compare them and help me wrap my >> head around them? I am going to look at the query plans in more detail >> when I have more time later but any thoughts help :) > > I loaded 1M, 2M and 3M rows into Table1, Table2 and Table3 respectively > using the script below. When I examined the execution plans of both > queries in a single batch, mine showed a relative cost of 43% vs. 57% for > yours. However, when I removed the extraneous GROUP BY from your query, > the costs and plans were identical. I guess the optimizer did it's job > ;-) > > Since rodchar didn't provide the actual schema (including indexes), we can > only guess what performance might be the the actual environment. > > > TRUNCATE TABLE dbo.Table1 > TRUNCATE TABLE dbo.Table2 > TRUNCATE TABLE dbo.Table3 > > INSERT INTO dbo.Table1 > SELECT Nums.ID, 'john', 'smith' > FROM > ( > SELECT Num1.Num + 1 + (Num2.Num * 10) + (Num3.Num * 100) + > (Num4.Num * 1000) + (Num5.Num * 10000) + (Num6.Num * 100000) AS ID > FROM ( > SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > SELECT 3 > UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > AS Num1 > CROSS JOIN ( > SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > SELECT 3 > UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > AS Num2 > CROSS JOIN ( > SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > SELECT 3 > UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > AS Num3 > CROSS JOIN ( > SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > SELECT 3 > UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > AS Num4 > CROSS JOIN ( > SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > SELECT 3 > UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > AS Num5 > CROSS JOIN ( > SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > SELECT 3 > UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > AS Num6 > ) AS Nums > > INSERT INTO dbo.Table2 > SELECT empId, '20050101', $25 > FROM dbo.Table1 > UNION ALL > SELECT empId, '20060101', $50 > FROM dbo.Table1 > > INSERT INTO dbo.Table3 > SELECT empId, '20050101', '20050601', 'director' FROM dbo.Table1 > UNION ALL SELECT empId, '20050602', '20051231', 'executive' FROM > dbo.Table1 > UNION ALL SELECT empId, '20060101', NULL, 'ceo' FROM dbo.Table1 > > UPDATE STATISTICS dbo.Table1 > UPDATE STATISTICS dbo.Table2 > UPDATE STATISTICS dbo.Table3 > GO > > > -- > Hope this helps. > > Dan Guzman > SQL Server MVP > > "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message > news:eSDkYVznHHA.5032@TK2MSFTNGP02.phx.gbl... >> Which actually brings up a question in my mind. Why does the version I >> wrote perform better? I would actually though Dan's would have from past >> experience with complex join conditions (like on involving an = >> comparison to a subquery). >> >> Dan if you have a few moments could you compare them and help me wrap my >> head around them? I am going to look at the query plans in more detail >> when I have more time later but any thoughts help :) >> >> Here is my version which should work with your DDL, Dan. >> >> select t1.empID, t1.fname + ' ' + t1.lname, tt2.salary , tt3.jobposition >> >> from table1 as t1 >> >> inner join table2 tt2 >> >> on t1.empid = tt2.empid >> >> and tt2.effective_date = (select max(table2.effective_date) from Table2 >> >> where table2.empId = tt2.empid >> >> group by table2.empid) >> >> inner join table3 tt3 >> >> on t1.empid = tt3.empid >> >> and tt3.start_date = (select max(table3.start_date) from table3 >> >> where table3.empid = tt3.empid) >> >> "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message >> news:OeodYRznHHA.4192@TK2MSFTNGP06.phx.gbl... >>> Or Dan's solution also works :) >>> >>> They should both give you what you are looking for. I think Dan's is >>> prettier with using the derived table rather than using correlated >>> subqueries as I did in the join's ON clause. I just ran Dan's create >>> table scripts and compared the two. They both gave the same results with >>> close performance. The one I posted performed a bit better but this is >>> not a real world test with such small tables and I am not sure which >>> would perform better for a large table. >>> >>> "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message >>> news:F5902945-7587-4FBC-B176-6C8CBB8187F1@microsoft.com... >>>>> could this be done in one uncomplicated sql statement? >>>> >>>> It depends what you mean by uncomplicated. The method below uses >>>> derived tables: >>>> >>>> CREATE TABLE dbo.Table1 >>>> ( >>>> empId int NOT NULL >>>> CONSTRAINT PK_Table1 PRIMARY KEY, >>>> fname varchar(30) NOT NULL, >>>> lname varchar(30) NOT NULL >>>> ) >>>> GO >>>> >>>> INSERT INTO dbo.Table1 >>>> SELECT 1,'john','smith' >>>> GO >>>> >>>> CREATE TABLE dbo.Table2 >>>> ( >>>> empId int NOT NULL, >>>> effective_date datetime NOT NULL, >>>> salary money NOT NULL, >>>> CONSTRAINT PK_Table2 PRIMARY KEY >>>> ( >>>> empId, >>>> effective_date >>>> ) >>>> ) >>>> GO >>>> >>>> INSERT INTO dbo.Table2 >>>> SELECT 1, '20050101', $25 >>>> UNION ALL SELECT 1, '20060101', $50 >>>> GO >>>> >>>> CREATE TABLE dbo.Table3 >>>> ( >>>> empId int NOT NULL, >>>> start_date datetime NOT NULL, >>>> end_date datetime NULL, >>>> jobPosition varchar(30) NOT NULL, >>>> CONSTRAINT PK_Table3 PRIMARY KEY >>>> ( >>>> empId, >>>> start_date >>>> ) >>>> ) >>>> >>>> INSERT INTO dbo.Table3 >>>> SELECT 1, '20050101', '20050601', 'director'
Heres another variant for SQL 2k5 but quickly falls behind the others in terms of performance with over 100 employees. SELECT t1.empId, t1.fname + ' ' + t1.lname AS FullName, t2.CurrentSalary, t3.CurrentPosition FROM dbo.Table1 AS t1 OUTER APPLY ( SELECT Top 1 salary AS CurrentSalary FROM dbo.Table2 AS it2 WHERE t1.empid=it2.empid ORDER BY effective_date DESC ) t2 OUTER APPLY ( SELECT Top 1 jobPosition AS CurrentPosition FROM dbo.Table3 AS it3 WHERE t1.empid=it3.empid ORDER BY start_date DESC ) t3 Mr Tea [quoted text, click to view] "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message news:eTjH4rznHHA.4132@TK2MSFTNGP02.phx.gbl... > thanks. That was strange. I was getting 43 for mine and 57 for yours. > (without inserting the higher sample data). I took out the group by you > pointed out :) (I was going down a different path first and left that) and > then each query was good at 50%.. > > But on your machine with my oops group by your plan had the 43 and mine > had the 57 (percent of total relative cost) mirror plans. I guess my > machine favors me <eg> > > Thanks for your time. > "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message > news:1F16EFCF-E5BB-45FA-9C76-7C7CC7CE3305@microsoft.com... >>> Dan if you have a few moments could you compare them and help me wrap my >>> head around them? I am going to look at the query plans in more detail >>> when I have more time later but any thoughts help :) >> >> I loaded 1M, 2M and 3M rows into Table1, Table2 and Table3 respectively >> using the script below. When I examined the execution plans of both >> queries in a single batch, mine showed a relative cost of 43% vs. 57% for >> yours. However, when I removed the extraneous GROUP BY from your query, >> the costs and plans were identical. I guess the optimizer did it's job >> ;-) >> >> Since rodchar didn't provide the actual schema (including indexes), we >> can only guess what performance might be the the actual environment. >> >> >> TRUNCATE TABLE dbo.Table1 >> TRUNCATE TABLE dbo.Table2 >> TRUNCATE TABLE dbo.Table3 >> >> INSERT INTO dbo.Table1 >> SELECT Nums.ID, 'john', 'smith' >> FROM >> ( >> SELECT Num1.Num + 1 + (Num2.Num * 10) + (Num3.Num * 100) + >> (Num4.Num * 1000) + (Num5.Num * 10000) + (Num6.Num * 100000) AS ID >> FROM ( >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL >> SELECT 3 >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) >> AS Num1 >> CROSS JOIN ( >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL >> SELECT 3 >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) >> AS Num2 >> CROSS JOIN ( >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL >> SELECT 3 >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) >> AS Num3 >> CROSS JOIN ( >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL >> SELECT 3 >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) >> AS Num4 >> CROSS JOIN ( >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL >> SELECT 3 >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) >> AS Num5 >> CROSS JOIN ( >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL >> SELECT 3 >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) >> AS Num6 >> ) AS Nums >> >> INSERT INTO dbo.Table2 >> SELECT empId, '20050101', $25 >> FROM dbo.Table1 >> UNION ALL >> SELECT empId, '20060101', $50 >> FROM dbo.Table1 >> >> INSERT INTO dbo.Table3 >> SELECT empId, '20050101', '20050601', 'director' FROM dbo.Table1 >> UNION ALL SELECT empId, '20050602', '20051231', 'executive' FROM >> dbo.Table1 >> UNION ALL SELECT empId, '20060101', NULL, 'ceo' FROM dbo.Table1 >> >> UPDATE STATISTICS dbo.Table1 >> UPDATE STATISTICS dbo.Table2 >> UPDATE STATISTICS dbo.Table3 >> GO >> >> >> -- >> Hope this helps. >> >> Dan Guzman >> SQL Server MVP >> >> "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message >> news:eSDkYVznHHA.5032@TK2MSFTNGP02.phx.gbl... >>> Which actually brings up a question in my mind. Why does the version I >>> wrote perform better? I would actually though Dan's would have from past >>> experience with complex join conditions (like on involving an = >>> comparison to a subquery). >>> >>> Dan if you have a few moments could you compare them and help me wrap my >>> head around them? I am going to look at the query plans in more detail >>> when I have more time later but any thoughts help :) >>> >>> Here is my version which should work with your DDL, Dan. >>> >>> select t1.empID, t1.fname + ' ' + t1.lname, tt2.salary , tt3.jobposition >>> >>> from table1 as t1 >>> >>> inner join table2 tt2 >>> >>> on t1.empid = tt2.empid >>> >>> and tt2.effective_date = (select max(table2.effective_date) from Table2 >>> >>> where table2.empId = tt2.empid >>> >>> group by table2.empid) >>> >>> inner join table3 tt3 >>> >>> on t1.empid = tt3.empid >>> >>> and tt3.start_date = (select max(table3.start_date) from table3 >>> >>> where table3.empid = tt3.empid) >>> >>> "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message >>> news:OeodYRznHHA.4192@TK2MSFTNGP06.phx.gbl... >>>> Or Dan's solution also works :) >>>> >>>> They should both give you what you are looking for. I think Dan's is >>>> prettier with using the derived table rather than using correlated >>>> subqueries as I did in the join's ON clause. I just ran Dan's create >>>> table scripts and compared the two. They both gave the same results >>>> with close performance. The one I posted performed a bit better but >>>> this is not a real world test with such small tables and I am not sure >>>> which would perform better for a large table. >>>> >>>> "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message >>>> news:F5902945-7587-4FBC-B176-6C8CBB8187F1@microsoft.com... >>>>>> could this be done in one uncomplicated sql statement? >>>>> >>>>> It depends what you mean by uncomplicated. The method below uses >>>>> derived tables: >>>>> >>>>> CREATE TABLE dbo.Table1 >>>>> ( >>>>> empId int NOT NULL >>>>> CONSTRAINT PK_Table1 PRIMARY KEY, >>>>> fname varchar(30) NOT NULL, >>>>> lname varchar(30) NOT NULL >>>>> ) >>>>> GO >>>>>
Thank you everyone for the great feedback. I appreciate very much. Rod. [quoted text, click to view] "rodchar" wrote: > hey all, > > Table1 > empId,fname,lname > 1,john,smith > > Table2 > empId,date,salary > 1,1/1/2005,$25 > 1,1/1/2006,$50 > Table3 > empId,startDate, endDate, jobPosition > 1,1/1/2005,6/1/2005,director > 1,6/2/2005,12/31/2005,executive > 1/1/2006,null,ceo > > i'd like to have a report like the following: > empID,fname + lname, current salary, current position > > could this be done in one uncomplicated sql statement? > > thanks,
Still there anyone? Bueler? Hey I have a new question regarding this old post if I may. What if Table2 and Table3 had some null records for a particular employee and I list all of those employees only. I tried appending "WHERE Salary = Null" to the encompassing SELECT statement but it didn't work. any ideas? thanks, rodchar [quoted text, click to view] "Mr Tea" wrote: > Heres another variant for SQL 2k5 but quickly falls behind the others in > terms of performance with over 100 employees. > > SELECT > t1.empId, > t1.fname + ' ' + t1.lname AS FullName, > t2.CurrentSalary, > t3.CurrentPosition > FROM dbo.Table1 AS t1 > OUTER APPLY ( > SELECT Top 1 salary AS CurrentSalary > FROM dbo.Table2 AS it2 > WHERE t1.empid=it2.empid > ORDER BY effective_date DESC > ) t2 > OUTER APPLY ( > SELECT Top 1 jobPosition AS CurrentPosition > FROM dbo.Table3 AS it3 > WHERE t1.empid=it3.empid > ORDER BY start_date DESC > ) t3 > Mr Tea > > "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message > news:eTjH4rznHHA.4132@TK2MSFTNGP02.phx.gbl... > > thanks. That was strange. I was getting 43 for mine and 57 for yours. > > (without inserting the higher sample data). I took out the group by you > > pointed out :) (I was going down a different path first and left that) and > > then each query was good at 50%.. > > > > But on your machine with my oops group by your plan had the 43 and mine > > had the 57 (percent of total relative cost) mirror plans. I guess my > > machine favors me <eg> > > > > Thanks for your time. > > "Dan Guzman" <guzmanda@nospam-online.sbcglobal.net> wrote in message > > news:1F16EFCF-E5BB-45FA-9C76-7C7CC7CE3305@microsoft.com... > >>> Dan if you have a few moments could you compare them and help me wrap my > >>> head around them? I am going to look at the query plans in more detail > >>> when I have more time later but any thoughts help :) > >> > >> I loaded 1M, 2M and 3M rows into Table1, Table2 and Table3 respectively > >> using the script below. When I examined the execution plans of both > >> queries in a single batch, mine showed a relative cost of 43% vs. 57% for > >> yours. However, when I removed the extraneous GROUP BY from your query, > >> the costs and plans were identical. I guess the optimizer did it's job > >> ;-) > >> > >> Since rodchar didn't provide the actual schema (including indexes), we > >> can only guess what performance might be the the actual environment. > >> > >> > >> TRUNCATE TABLE dbo.Table1 > >> TRUNCATE TABLE dbo.Table2 > >> TRUNCATE TABLE dbo.Table3 > >> > >> INSERT INTO dbo.Table1 > >> SELECT Nums.ID, 'john', 'smith' > >> FROM > >> ( > >> SELECT Num1.Num + 1 + (Num2.Num * 10) + (Num3.Num * 100) + > >> (Num4.Num * 1000) + (Num5.Num * 10000) + (Num6.Num * 100000) AS ID > >> FROM ( > >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > >> SELECT 3 > >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > >> AS Num1 > >> CROSS JOIN ( > >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > >> SELECT 3 > >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > >> AS Num2 > >> CROSS JOIN ( > >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > >> SELECT 3 > >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > >> AS Num3 > >> CROSS JOIN ( > >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > >> SELECT 3 > >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > >> AS Num4 > >> CROSS JOIN ( > >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > >> SELECT 3 > >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > >> AS Num5 > >> CROSS JOIN ( > >> SELECT 0 AS Num UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL > >> SELECT 3 > >> UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 > >> UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) > >> AS Num6 > >> ) AS Nums > >> > >> INSERT INTO dbo.Table2 > >> SELECT empId, '20050101', $25 > >> FROM dbo.Table1 > >> UNION ALL > >> SELECT empId, '20060101', $50 > >> FROM dbo.Table1 > >> > >> INSERT INTO dbo.Table3 > >> SELECT empId, '20050101', '20050601', 'director' FROM dbo.Table1 > >> UNION ALL SELECT empId, '20050602', '20051231', 'executive' FROM > >> dbo.Table1 > >> UNION ALL SELECT empId, '20060101', NULL, 'ceo' FROM dbo.Table1 > >> > >> UPDATE STATISTICS dbo.Table1 > >> UPDATE STATISTICS dbo.Table2 > >> UPDATE STATISTICS dbo.Table3 > >> GO > >> > >> > >> -- > >> Hope this helps. > >> > >> Dan Guzman > >> SQL Server MVP > >> > >> "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message > >> news:eSDkYVznHHA.5032@TK2MSFTNGP02.phx.gbl... > >>> Which actually brings up a question in my mind. Why does the version I > >>> wrote perform better? I would actually though Dan's would have from past > >>> experience with complex join conditions (like on involving an = > >>> comparison to a subquery). > >>> > >>> Dan if you have a few moments could you compare them and help me wrap my > >>> head around them? I am going to look at the query plans in more detail > >>> when I have more time later but any thoughts help :) > >>> > >>> Here is my version which should work with your DDL, Dan. > >>> > >>> select t1.empID, t1.fname + ' ' + t1.lname, tt2.salary , tt3.jobposition > >>> > >>> from table1 as t1 > >>> > >>> inner join table2 tt2 > >>> > >>> on t1.empid = tt2.empid > >>> > >>> and tt2.effective_date = (select max(table2.effective_date) from Table2 > >>> > >>> where table2.empId = tt2.empid > >>> > >>> group by table2.empid) > >>> > >>> inner join table3 tt3 > >>> > >>> on t1.empid = tt3.empid > >>> > >>> and tt3.start_date = (select max(table3.start_date) from table3 > >>> > >>> where table3.empid = tt3.empid) > >>> > >>> "Mike Walsh" <[mwalsh9815][at][gmail][dot][com]> wrote in message > >>> news:OeodYRznHHA.4192@TK2MSFTNGP06.phx.gbl... > >>>> Or Dan's solution also works :) > >>>> > >>>> They should both give you what you are looking for. I think Dan's is > >>>> prettier with using the derived table rather than using correlated > >>>> subqueries as I did in the join's ON clause. I just ran Dan's create > >>>> table scripts and compared the two. They both gave the same results
Thank you for the help. [quoted text, click to view] "Aaron Bertrand [SQL Server MVP]" wrote: > > I tried appending "WHERE Salary = Null" > > You can't compare NULL using equality. Since NULL is, by definition, > "unknown" then it is impossible to say it whether is equal to or, more > importantly, NOT equal to something. > > Perhaps you meant > > WHERE Salary IS NULL > or > WHERE Salary IS NOT NULL > >
[quoted text, click to view] > I tried appending "WHERE Salary = Null"
You can't compare NULL using equality. Since NULL is, by definition, "unknown" then it is impossible to say it whether is equal to or, more importantly, NOT equal to something. Perhaps you meant WHERE Salary IS NULL or WHERE Salary IS NOT NULL
Don't see what you're looking for? Try a search.
|