How can I combine SQL queries with different expressions?

不问归期 提交于 2019-12-23 19:28:47

问题


I've got three queries that are already at the peak of my SQL knowledge (Microsoft SQL 2005, if that matters) - and now I need to combine them into a single query with all of the values on a single row.

My actual queries are below, but I thought it'd be easier if I provided a simple version here:

Query One:

-- Provides School District summary based on a CountyID
SELECT DistrictID, Count(Schools) as NumberofSchools
FROM Schools
WHERE (CountyID = 207)
GROUP BY DistrictID

Query One Sample Output:

DistrictID  |  NumberofSchools
345         |  26
567         |  17
211         |  9

Query Two:

-- Summarizes Activity from our Contact Manager (GoldMine)
SELECT DistrictID, Count(Contacts) as NumberofContacts, MAX(Contact) as LastActivity
FROM ContactManager JOINED WITH CONTACT MANAGER TABLES
WHERE (CountyID = 207)
GROUP BY DistrictID

Query Two Sample Output:

DistrictID  |  NumberofContacts  |  LastActivity
345         |  29                |  Nov 12, 2010
567         |  31                |  Dec 5, 2010
211         |  4                 |  Oct 9, 2010

Query Three:

-- Summarizes data from our Opt-In Email Newsletter
SELECT DistrictID, Count(EmailSubscribers) AS NumberofSubscribers, MAX(Date) AS LastSent
FROM SubscribeList JOINED WITH Schools Tables
WHERE (CountyID = 207)
GROUP BY DistrictID

Query Three Sample Output:

DistrictID  |  NumberofSubscribers  |  LastSent
345         |  2                    |  Sep 4, 2010
567         |  3                    |  Oct 22, 2010
211         |  1                    |  NULL

I've tried making a huge UNION of them with a parent SELECT statement, (following details from this weblink and by introducting SELECT NULL AS MissingColumnName for each dataset) but it's really ugly - and doesn't return everything on one row.

I'm looking for results like this:

DistrictID  |  NumberofSchools  |  NumberofContacts  |  LastActivity  |  NumberofSubscribers  |  LastSent
345         |  26               |  29                |  Nov 12, 2010  |  2                     |  Sep 4, 2010
567         |  17               |  31                |  Dec 5, 2010   |  3                     |  Oct 22, 2010 
211         |  9                |  4                 |  Oct 9, 2010   |  1                     |  NULL

How can I make this work? (And if you're curious, the real queries I'm joining are below)

Thanks for all your help!,

Russell Schutte

Cleaned up these as best I can - sorry they don't display really nice. (There may be issues with these too - they're at the top of my SQL knowledge, but so far the results seem accurate.) :-)

Query One:

SELECT
    institutionswithzipcodesadditional_1.DistrictID, institutionswithzipcodesadditional_1.InstitutionName, institutionswithzipcodesadditional_1.Latitude, institutionswithzipcodesadditional_1.Longitude,
    SUM(CASE WHEN institutionswithzipcodesadditional.LevelID IN (4, 5, 6, 7, 8, 14, 15, 16, 20) THEN institutionswithzipcodesadditional.Enrollment ELSE 0 END) AS OthersEnrollment,
    COUNT(CASE WHEN institutionswithzipcodesadditional.LevelID IN (4, 5, 6, 7, 8, 14, 15, 16, 20) THEN institutionswithzipcodesadditional.InstitutionID ELSE NULL END) AS OthersCount, 
    SUM(CASE WHEN institutionswithzipcodesadditional.LevelID IN (13) THEN institutionswithzipcodesadditional.Enrollment ELSE 0 END) AS K12SchoolsEnrollment, 
    COUNT(CASE WHEN institutionswithzipcodesadditional.LevelID IN (13) THEN institutionswithzipcodesadditional.InstitutionID ELSE NULL END) AS K12SchoolsCount, 
    SUM(CASE WHEN institutionswithzipcodesadditional.LevelID IN (12) THEN institutionswithzipcodesadditional.Enrollment ELSE 0 END) AS HighSchoolsEnrollment, 
    COUNT(CASE WHEN institutionswithzipcodesadditional.LevelID IN (12) THEN institutionswithzipcodesadditional.InstitutionID ELSE NULL END) AS HighSchoolsCount, 
    SUM(CASE WHEN institutionswithzipcodesadditional.LevelID IN (10, 11) THEN institutionswithzipcodesadditional.Enrollment ELSE 0 END) AS MiddleSchoolsEnrollment,
    COUNT(CASE WHEN institutionswithzipcodesadditional.LevelID IN (10, 11) THEN institutionswithzipcodesadditional.InstitutionID ELSE NULL END) AS MiddleSchoolsCount,
    SUM(CASE WHEN institutionswithzipcodesadditional.LevelID IN (9) THEN institutionswithzipcodesadditional.Enrollment ELSE 0 END) AS ElementariesEnrollment,
    COUNT(CASE WHEN institutionswithzipcodesadditional.LevelID IN (9) THEN institutionswithzipcodesadditional.InstitutionID ELSE NULL END) AS ElementariesCount,
    SUM(CASE WHEN institutionswithzipcodesadditional.LevelID IN (4, 5, 6, 7, 8, 14, 15, 16, 20, 13, 12, 10, 11, 9) THEN institutionswithzipcodesadditional.Enrollment ELSE 0 END) AS AllSchoolsEnrollment, 
    COUNT(CASE WHEN institutionswithzipcodesadditional.LevelID IN (4, 5, 6, 7, 8, 14, 15, 16, 20, 13, 12, 10, 11, 9) THEN institutionswithzipcodesadditional.InstitutionID ELSE NULL END) AS AllSchoolsCount
FROM zipcodes 
    INNER JOIN users_link_territory ON zipcodes.CountyID = users_link_territory.CountyID
    INNER JOIN institutionswithzipcodesadditional ON zipcodes.ZIP = institutionswithzipcodesadditional.ZIP
    RIGHT OUTER JOIN institutionswithzipcodesadditional AS institutionswithzipcodesadditional_1 ON institutionswithzipcodesadditional.DistrictID = institutionswithzipcodesadditional_1.InstitutionID
WHERE
    (institutionswithzipcodesadditional_1.CountyID = 207)
AND (institutionswithzipcodesadditional_1.LevelID IN (1, 2, 3, 6, 7, 8))
GROUP BY institutionswithzipcodesadditional_1.DistrictID, institutionswithzipcodesadditional_1.InstitutionName, institutionswithzipcodesadditional_1.Latitude, institutionswithzipcodesadditional_1.Longitude

Query Two:

SELECT
institutionswithzipcodesadditional_1.InstitutionID AS DistrictID,
COUNT(GoldMine.dbo.CONTACT1.ACCOUNTNO) AS GM,
MAX(CASE WHEN GoldMine.dbo.CONTHIST.USERID NOT IN ('DEBRA', 'TRISH', 'RUSSELL', 'GREG') THEN GoldMine.dbo.CONTHIST.OnDate ELSE NULL END) AS LastActivity
FROM institutionswithzipcodesadditional
    LEFT OUTER JOIN contacts
    LEFT OUTER JOIN GoldMine.dbo.CONTACT1
    RIGHT OUTER JOIN GoldMine_Link_Russell 
    ON GoldMine.dbo.CONTACT1.KEY3 = GoldMine_Link_Russell.GoldMineKeyThree
    ON contacts.ContactID = GoldMine_Link_Russell.ContactID 
    ON institutionswithzipcodesadditional.InstitutionID = contacts.InstitutionID
    RIGHT OUTER JOIN institutionswithzipcodesadditional AS institutionswithzipcodesadditional_1
    ON institutionswithzipcodesadditional.DistrictID = institutionswithzipcodesadditional_1.InstitutionID
    LEFT OUTER JOIN GoldMine.dbo.CONTHIST ON GoldMine.dbo.CONTHIST.ACCOUNTNO = GoldMine.dbo.CONTACT1.ACCOUNTNO
WHERE (institutionswithzipcodesadditional_1.CountyID = 207) AND (institutionswithzipcodesadditional_1.LevelID IN (1, 2, 3, 6, 7, 8))
GROUP BY institutionswithzipcodesadditional_1.InstitutionID

Query Three:

SELECT
COUNT(NewsletterContacts.Email) AS EMailableContacts,
institutionswithzipcodesadditional_1.InstitutionID AS DistrictID,
MAX(newsletterregister.Sent) AS LastSent
FROM newsletterregister
    RIGHT OUTER JOIN contacts ON newsletterregister.ContactID = contacts.ContactID
    RIGHT OUTER JOIN institutionswithzipcodesadditional ON contacts.InstitutionID = institutionswithzipcodesadditional.InstitutionID
    LEFT OUTER JOIN EmailableContacts ON institutionswithzipcodesadditional.InstitutionID = EmailableContacts.InstitutionID
    RIGHT OUTER JOIN institutionswithzipcodesadditional AS institutionswithzipcodesadditional_1 ON 
    institutionswithzipcodesadditional.DistrictID = institutionswithzipcodesadditional_1.InstitutionID
WHERE
    (institutionswithzipcodesadditional_1.CountyID = 207)
    AND (institutionswithzipcodesadditional_1.LevelID IN (1, 2, 3, 6, 7, 8))
GROUP BY institutionswithzipcodesadditional_1.InstitutionID

回答1:


I stole part of Mark's solution, but I wanted to show you this layout for its readability. That way you don't have all three queries jammed into the one select statement. This gives you some of a maintainability benefits you might get with a temp table or table variables, but the below is much more flexible to change, because you don't have to mess with table declarations everytime you add/remove columns.

With SomeGoodName as
(
  SELECT ...
)
,
AnotherDescriptiveName as
(
  Select ...
)
,
AThirdNiceName as
(
  Select ...
)
SELECT
    T1.DistrictID,
    T1.NumberofSchools,
    T2.NumberofContacts,
    T2.LastActivity,
    T3.NumberofSubscribers,
    T3.LastSent
FROM SomeGoodName T1
JOIN AnotherDescriptiveName T2 ON T1.DistrictID = T2.DistrictID
JOIN AThirdNiceName T3 ON T1.DistrictID = T3.DistrictID



回答2:


Yes, you can do that using joins:

SELECT
    T1.DistrictID,
    T1.NumberofSchools,
    T2.NumberofContacts,
    T2.LastActivity,
    T3.NumberofSubscribers,
    T3.LastSent
FROM (SELECT ...) T1
JOIN (SELECT ...) T2 ON T1.DistrictID = T2.DistrictID
JOIN (SELECT ...) T3 ON T1.DistrictID = T3.DistrictID

The (SELECT ...) are placeholders for your three original queries. You may also want to consider using OUTER JOINs if the three queries could return different districts, i.e. if a district is present in the result of one query but missing in another.




回答3:


You are going to get a number of answers here, and while I would agree that you "could" get this all into a single select, I think you are going to have an easier to maintain and easier to run process if you work a bit with some temporary tables or similar.

For example, create temporary tables to store the results of each of your three queries, then join the three temp tables together to get the final result and destroy the temp tables afterwards.

This way you can keep the queries doing what they are doing, and you can focus on final aggregation.

You could do this using the individual queries as from items as another poster has mentioned, but that can get VERY hard to maintain.



来源:https://stackoverflow.com/questions/4557722/how-can-i-combine-sql-queries-with-different-expressions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!