Convert a SQL subquery into a join when looking at another record in the same table Access 2010

徘徊边缘 提交于 2019-12-01 10:38:14

问题


I have read that Joins are more efficient than subqueries, I have a query that is extremely slow and uses lots of subqueries, therefore I would like to improve it but do not know how.

I have the following tables:

 People  \\this table stores lists of individual people with the following fields
 ( 
    ID, \\Primary Key
    aacode Text, \\represents a individual house
    PERSNO number, \\represent the number of the person in the house e.g. person number 1
    HRP number, \\the PERSNO of the Housing Reference Person (HRP) the "main" person in the house
    DVHsize number, \\the number of people in the house
    R01 number, \\the persons relationship to the person who is PERSNO=1
    R02 number, \\the persons relationship to the person who is PERSNO=2
    R03 number, \\the persons relationship to the person who is PERSNO=3
    AgeCat text, \\the age range of the person e.g. 30-44
    xMarSta number, \\representing the marital satus of the person
)
Relatives \\this table stores the possible R01 numbers and their text equivalents
(
    ID Primary Key, \\all possible R01 values
    Relationship text, \\meaning of the corisponding R01 values
)
xMarSta \\this table store the possible xMarSta values and their text equivalents
(
    ID Primary Key \\all possible xMarSta values
    Marital text, \\meaning of corresponding R01 values
)

The query is:

HsHld - the goal of this query is to produce for each house (i.e. each aacode) a text sting describing the house in the form [Marital][AgeCat][Relationship][AgeCat][Relationship][AgeCat] etc. So an output for a three person house might look like Married(30-44)Spouse(30-44)Child(1-4)

I know my current code for HsHld is terrible, but it is included below:

SELECT People.ID, People.aacode, People.PERSNO, 
       People.HRP, People.DVHsize, xMarSta.Marital,
       [Marital] & " (" & [AgeCat] & ")" & [RAL2] & [RAge2] & 
       [RAL3] & [RAge3] & [RAL4] & [RAge4] & [RAL5] & [RAge5] & 
       [RAL6] & [RAge6] & [RAL7] & [RAge7] & [RAL8] & [RAge8] AS HsTyp,
       (SELECT Fam2.R01  FROM People  AS Fam2  WHERE Fam2.aacode = People.aacode 
        AND Fam2.PERSNO = 2) AS Rel2,
       (SELECT Fam3.R01  FROM People  AS Fam3  WHERE Fam3.aacode = People.aacode 
        AND Fam3.PERSNO = 3) AS Rel3,
       Switch([Rel2] Is Null,Null,[Rel2]=-9,'DNA',[Rel2]=-8,'NoAns',
              [Rel2]=1,'Spouse',[Rel2]=2,'Cohabitee',[Rel2]<7,'Child',
              [Rel2]<10,'Parent',[Rel2]<15,'Sibling',[Rel2]=15,'Grandchild',
              [Rel2]=16,'Grandparent',[Rel2]=17,'OtherRelative',
              [Rel2]=20,'CivilPartner',True,'Other') AS RAL2,
       Switch([Rel3] Is Null,Null,[Rel3]=-9,'DNA',[Rel3]=-8,'NoAns',
              [Rel3]=1,'Spouse',[Rel3]=2,'Cohabitee',[Rel3]<7,'Child',
              [Rel3]<10,'Parent',[Rel3]<15,'Sibling',[Rel3]=15,'Grandchild',
              [Rel3]=16,'Grandparent',[Rel3]=17,'OtherRelative',
              [Rel3]=20,'CivilPartner',True,'Other') AS RAL3,
       (Select FAge2.AgeCat FROM People AS FAge2 
               WHERE FAge2.aacode = People.aacode 
               AND FAge2.PERSNO = 2
       ) AS RAge2,
       (Select FAge3.AgeCat FROM People AS FAge3 
               WHERE FAge3.aacode = People.aacode AND FAge3.PERSNO = 3
       ) AS RAge3
FROM Relatives 
RIGHT JOIN (xMarSta RIGHT JOIN People ON xMarSta.ID=People.xMarSta) 
           ON Relatives.ID=People.R01
WHERE (((People.HRP)=[People.PERSNO]))
ORDER BY People.aacode;

There are several key things that need to change.

  1. At the moment I can't get a join from the Rel field to the Relatives table to work, so I am using a Switch function called RAL there must be a better way.
  2. For simplicity in the post I have only included Rel2 & Rel3 etc but in the actual code it goes up to Rel13! So the problem of performance is even worse.
  3. I want to replace these subqueries with joins, but as the subquery looks into another record in the same table I am unsure how to go about this.
  4. I'm very out of my depth with this, I know a little SQL but the complexity of this problem is too much for my limited knowledge

回答1:


The very first thing is that you have a relational situation but the table structure you have is using columns to represent relationships. This gives you the R01, R02, R03 ... R13 columns on your table. Unfortunately you will not be able to change performance dramatically because your table structure is repetitive denormalized instead of relational. This means that your query will need all this repetitive code, as you mentioned repeating 13 times. That also means that your switch function can be replaced by a join but again will be repeated 13 times.

Right, now back to your query, you have multiple sub-selects on your query and you need to join the related tables on a left join on the FROM clause and use the new related alias on your select. now you will see on the example below that for each R01, R02 field you will have a Fam2, Fam3 relation and you will need to do this 13 times on your case, and for each one you need to link to the relatives table (as i did called Relat2, Relat3, etc). Now if you can change your database structure for a normalized structure, you could really simplify this query and use much simpler joins.

See if this one helps you understand the process:

SELECT People.ID, People.aacode, People.PERSNO,  
       People.HRP, People.DVHsize, xMarSta.Marital, 
       [Marital] & " (" & [People.AgeCat] & ")" & [RAL2] & [RAge2] &  
       [RAL3] & [RAge3] AS HsTyp, 
       Fam2.R01 AS Rel2,
       Fam3.R01 AS Rel3, 
       Relat2.Relationship as RAL2,
       Relat3.Relationship as RAL3,
       Fam2.AgeCat AS RAge2, 
       Fam3.AgeCat AS RAge3 
FROM (((((People
LEFT JOIN (People  AS Fam2) ON (Fam2.aacode = People.aacode  and Fam2.PERSNO = 2))
LEFT JOIN (Relatives as Relat2) on Relat2.Id = Fam2.R01)
LEFT JOIN (People as Fam3)   ON (Fam3.aacode = People.aacode  AND Fam3.PERSNO = 3))
LEFT JOIN (Relatives as Relat3) on Relat3.Id = Fam3.R01)
LEFT JOIN xMarSta ON xMarSta.ID=People.xMarSta)
WHERE (People.HRP=[People.PERSNO])
ORDER BY People.aacode; 



回答2:


Joining a table to it self is done with an alias

e.g.

Select * From [Table1] Join [Table1] t1 on T1.SomeField = Table1.SomeOtherField

etc..

Probaly won't have time to fix it, but the real problem is where you've denormalised with R01, R02 etc.

You should have an other table RelationshipID PersonFrom PersonTo

You need to manage that though when creating relations and it will mean changes to your UI and logic.



来源:https://stackoverflow.com/questions/8136392/convert-a-sql-subquery-into-a-join-when-looking-at-another-record-in-the-same-ta

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