简体   繁体   中英

MySQL Query - SELECT 2 rows with 2 specific DISTINCT column values

My goal is, for each PID , to select 2 records with test_sname values of ' want ' and ' want2 ' that occur on the same entry_date . I do this for the first 5 entry_dates that include both test_snames .

This is my query for accomplishing this:

queryBuilder = 
"""select PID, test_sname, test_value, units, ref_range, entry_date from labs
   where PID=%s and (test_sname='want' or test_sname='want2') and entry_date in

   (select entry_date from labs where PID=%s and test_sname in ('want', 'want2')
   group by entry_date having count(*) = 2) 

   order by entry_date limit 10;""" % (pid, pid)

It works as expected when an entry_date has only two rows that contain a test_sname of ' want ' or ' want2 '.

PID      |test_sname  |test_value  |units    |entry_date
10000000 | want       |         343 | U/L     | 2008-01-01 01:01:01
10000000 | want2      |      984.34 |         | 2008-01-01 01:01:01
10000000 | NA1        |          56 | %       | 2008-01-01 01:01:01
10000000 | NA2        |         420 | mg/dL   | 2008-01-01 01:01:01
10000000 | NA2        |         420 | mg/dL   | 2008-01-02 01:01:01

10000000 | want       |         343 | U/L     | 2008-01-02 01:01:01
10000000 | want2      |      984.34 |         | 2008-01-02 01:01:01
10000000 | NA1        |          26 | %       | 2008-01-02 01:01:01
10000000 | NA2        |         410 | mg/dL   | 2008-01-02 01:01:01
10000000 | NA2        |         455 | mg/dL   | 2008-01-02 01:01:01

Results of Query (which are correct):

PID      |test_sname  |test_value  |units    |entry_date
10000000 | want       |         343 | U/L     | 2008-01-01 01:01:01
10000000 | want2      |      984.34 |         | 2008-01-01 01:01:01
10000000 | want       |         343 | U/L     | 2008-01-02 01:01:01
10000000 | want2      |      984.34 |         | 2008-01-02 01:01:01

The problem comes when, for instance, there are multiple rows from the test_sname of ' want ' on the same entry_date, because the having count(*) = 2 is no longer valid. There are no results for data like this.

PID      |test_sname  |test_value  |units    |entry_date
11111111 | want       |         343 | U/L     | 2009-10-26 07:25:00
11111111 | want2      |      984.34 |         | 2009-10-26 07:25:00
11111111 | want       |        189 | U/L     | 2009-10-26 07:25:00
11111111 | NA1        |         50 | %       | 2009-10-26 07:25:00
11111111 | NA2        |         40 | mg/dL   | 2009-10-26 07:25:00
11111111 | NA3        |      84.55 |         | 2009-10-26 07:25:00
11111111 | NA4        |        4.5 | thou/uL | 2009-10-26 07:25:00
11111111 | NA5        |       14.6 | g/dL    | 2009-10-26 07:25:00
11111111 | NA6        |       0.96 | mg/dL   | 2009-10-26 07:25:00

11111111 | want       |         343 | U/L     | 2009-10-30 07:25:00
11111111 | want2      |      984.34 |         | 2009-10-30 07:25:00
11111111 | want       |        189 | U/L     | 2009-10-30 07:25:00
11111111 | NA1        |          6 | %       | 2009-10-30 07:25:00
11111111 | NA2        |         40 | mg/dL   | 2009-10-30 07:25:00
11111111 | NA3        |      84.55 |         | 2009-10-30 07:25:00
11111111 | NA4        |        4.5 | thou/uL | 2009-10-30 07:25:00
11111111 | NA5        |       14.6 | g/dL    | 2009-10-30 07:25:00
11111111 | NA6        |       0.96 | mg/dL   | 2009-10-30 07:25:00

As a restriction, I tried putting a limit 2 in the subquery (I know that by itself that won't fix the problem), but it gave this error, and I thought I had the most updated version of SQL, so apparently I can't use limit in the subquery.

This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

I realize there are multiple ways to fix this - I could select ALL the values and then programmatically take what I need with Python, but I'm looking for a mySQL query solution written using the Python mySQL-connector. I wouldn't complain about a python solution though.

I am using python v3.4.4 with mySQL-connector v2.1.3 and MySQL server v5.7.11

Thanks for your time!

Consider using a running count of your grouping via a subquery. Then, filter wherever RowNo is 1 or 2. In this way, you would not need to pass a parameter as all PIDs will be handled. Below assumes the labs table has a unique identifier, ID :

SELECT * 
FROM
   (SELECT PID, test_sname, test_value, units, ref_range, entry_date,    
           (SELECT count(*) FROM labs sub
            WHERE sub.test_sname in ('want', 'want2')
            AND sub.PID = labs.PID
            AND sub.entry_date = labs.entry_date
            AND sub.ID <= labs.ID) As RowNo
    FROM labs
    WHERE test_sname in ('want', 'want2')
   ) As dT
WHERE dT.RowNo <= 2

#  PID     test_sname   test_value      units   ref_range              entry_date   RowNo
#  10000000      want           33        U/L        4-40     2008-01-01 01:01:01       1
#  10000000     want2        98.34                            2008-01-01 01:01:01       2
#  10000000      want           33        U/L        4-40     2008-01-02 01:01:01       1
#  10000000     want2        98.34                            2008-01-02 01:01:01       2
#  11111111      want           33        U/L      Apr-40     2009-10-26 07:25:00       1
#  11111111     want2        98.34                            2009-10-26 07:25:00       2
#  11111111      want           33        U/L      Apr-40     2009-10-30 07:25:00       1
#  11111111     want2        98.34                            2009-10-30 07:25:00       2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM