The location of the where keyword in the SQL connection query

I have been busy lately and don't have much time to stay and write a blog. In the evening, I encountered a SQL problem that I found very interesting, which may be helpful to beginners and rookies like me, so I decided to share it with everyone.

Because the author is inherently clumsy, and not rigorous in thinking, and is really not good at writing SQL statements, masters do not laugh, please skip this article.


I won’t introduce the background much. Create a table first and insert test data. Fields have comments

--医生表
CREATE TABLE doctor
    (
      id INT IDENTITY(1, 1) , --ID 自增长
      docNumber NVARCHAR(50) NOT NULL , --医生编码
      NAME NVARCHAR(50) NOT NULL   --医生姓名
    )
go

--插入测试数据
INSERT  INTO doctor
VALUES  ( '007', 'Tom' )
INSERT  INTO doctor
VALUES  ( '008', 'John' )
INSERT  INTO doctor
VALUES  ( '009', 'Jim' )


--号源表(挂号表)
CREATE TABLE Nosource
    (
      id INT IDENTITY(1, 1) ,
      docNumber NVARCHAR(50) NOT NULL , --和医生表中的医生编码对应
      workTime DATETIME NOT NULL
    )

go
--插入测试数据
INSERT  INTO Nosource
VALUES  ( '007', '20120819' )
INSERT  INTO Nosource
VALUES  ( '007', '20120820' )
INSERT  INTO Nosource
VALUES  ( '007', '20120821' )
INSERT  INTO Nosource
VALUES  ( '008', '20120821' )

After the table is built, the test data is also OK. Let’s start talking about demand.

1. Find out the relevant information of each doctor, and the number of sources owned by that doctor.

This is too simple, maybe even friends who have just learned helloWorld and a little database basics will be serious and sincere BS. But the code is still written.

--简单的分组查询即可搞定
SELECT  COUNT(nos.id) AS PersonNumSounceCOUNT , --总数
        dct.ID AS docID ,
        dct.NAME ,
        dct.docNumber ,
        nos.workTime
FROM    doctor AS dct
        LEFT JOIN Nosource AS nos ON dct.docNumber = nos.docNumber
GROUP BY dct.ID ,
        dct.NAME ,
        dct.docNumber ,
        nos.workTime

It's really simple. A small group can be done. What else are you selling?

Now that the demand changes, it needs to be matched according to the conditions: the workTime of the required number source table is greater than the current date to be valid, otherwise it will not match.
If the workTime condition does not match the doctor, the value of the corresponding PersonNumSounceCOUNT field should be 0; for example, if the doctor Jim does not have a matching and qualified number source, the value of the PersonNumSounceCOUNT field should be 0. Looking up at the sky 40 degrees, think about the ability to filter with the where keyword, and then query it all at once? Try it.

SELECT  COUNT(nos.id) AS PersonNumSounceCOUNT , --总数
        dct.ID ,
        dct.NAME ,
        dct.docNumber ,
        nos.workTime
FROM    doctor AS dct
        LEFT JOIN Nosource AS nos ON dct.docNumber = nos.docNumber
WHERE   DATEDIFF(day, GETDATE(), nos.workTime) > 0
GROUP BY dct.ID ,
        dct.NAME ,
        dct.docNumber ,
        nos.workTime

I believe someone will write the above code. But after executing the query, I found that it did not meet the requirements at all. Even Dr. Jim's basic information and table records have been filtered out and disappeared. What's the matter?

The reason is simple. Use the "where" keyword after the connection query to filter the data in the result set of the connection query. Because the conditions of the right table (number source table) do not match, the data in the left table (doctor table) will also be filtered out.

Therefore, the above phenomenon will occur (Dr. Jim's information and records are gone). Is it possible to find out all at once? How to achieve it?


In fact, the correct writing should be like this:

SELECT  COUNT(nos.id) AS PersonNumSounceCOUNT , --总数
        dct.ID ,
        dct.NAME ,
        dct.docNumber ,
        nos.workTime
FROM    doctor AS dct
        LEFT JOIN ( SELECT  *
                    FROM    Nosource
                    WHERE   DATEDIFF(day, GETDATE(), workTime) > 0
                  ) AS nos ON dct.docNumber = nos.docNumber
GROUP BY dct.ID ,
        dct.NAME ,
        dct.docNumber ,
        nos.workTime

Perform it again, and it turns out OK, which is the result of meeting the requirements. The idea is: only need to filter the right table, use the filtered result set (using a subquery) as the right table of the join query, and then connect and group...

In fact, writing concise and high-performance SQL statements requires strong logical thinking skills (inseparable from mathematics) and experience. There is a simpler way of writing:

SELECT  sum(case when nos.workTime>getdate then 1 else 0 end) AS PersonNumSounceCOUNT , --总数
dct.ID AS docID ,
dct.NAME ,
dct.docNumber 
FROM    doctor AS dct
LEFT JOIN Nosource AS nos ON dct.docNumber = nos.docNumber
GROUP BY dct.ID ,
dct.NAME ,
dct.docNumber 


To explain it this way, I don’t know if everyone can understand it. Anyway, the general idea is like this. The author's expressive ability and level are indeed limited, and it is inevitable that there will be deviations. I hope readers will understand!



This article is from http://blog.csdn.net/dinglang_2009 , please indicate the source for reprinting.





Guess you like

Origin blog.csdn.net/dinglang_2009/article/details/7888506