SELECT distinct values for multiple rows of same ID

后端 未结 5 1774
甜味超标
甜味超标 2020-12-17 03:03

I have a table that looks like this:

ID | FIELD_NAME   | VALUE
23 |  sign_up     |  yes
23 |  first_name  |  Fred
23 |  street      |  Barber Lane
24 |  sign         


        
相关标签:
5条回答
  • 2020-12-17 03:14

    You could also try pivoting with the help of grouping and conditional aggregating:

    SELECT
      ID,
      MAX(CASE FIELD_NAME WHEN 'sign_up'    THEN VALUE END) AS SIGN_UP,
      MAX(CASE FIELD_NAME WHEN 'first_name' THEN VALUE END) AS FIRST_NAME,
      MAX(CASE FIELD_NAME WHEN 'street'     THEN VALUE END) AS STREET
    FROM atable
    GROUP BY
      ID
    ;
    
    0 讨论(0)
  • 2020-12-17 03:14

    Adapted from another answer by me:

    SELECT ids.ID AS ID,
           sign_up.VALUE AS SIGN_UP,
           first_name.VALUE AS FIRST_NAME,
           street.VALUE AS STREET
    FROM (SELECT DISTINCT ID FROM tableName) AS ids
         LEFT JOIN tableName AS sign_up
                ON (sign_up.ID = ids.ID AND
                    sign_up.FIELD_NAME = 'sign_up')
         LEFT JOIN tableName AS first_name
                ON (first_name.ID = ids.ID AND
                    first_name.FIELD_NAME = 'first_name')
         LEFT JOIN tableName AS street
                ON (street.ID = ids.ID AND
                    street.FIELD_NAME = 'street')
    

    The left joins will ensure that missing values will result in NULL cells, instead of an omission of the whole row. Not sure whether that is important in your application. If it is not, you can use an inner join and in particular get rid of the subquery to select all unique IDs. See my original answer from which I derived this.

    0 讨论(0)
  • 2020-12-17 03:28

    One approach is to use a correlated subquery to return each field value as a column,

    SELECT t.id
         , (SELECT f1.value FROM mytable f1 
             WHERE f1.id = t.id AND f1.field_name = 'sign_up' 
             ORDER BY f1.value LIMIT 1
           ) AS SIGN_UP
         , (SELECT f2.value FROM mytable f2 
             WHERE f2.id = t.id AND f2.field_name = 'first_name' 
             ORDER BY f2.value LIMIT 1
           ) AS FIRST_NAME
         , (SELECT f3.value FROM mytable f3 
             WHERE f3.id = t.id AND f3.field_name = 'street'
             ORDER BY f3.value LIMIT 1
           ) AS STREET
      FROM (SELECT s.id
              FROM mytable s
             GROUP BY s.id
             ORDER BY s.id
           ) t
    

    This isn't the only way, but it's a workable approach, especially if you are concerned that you will get exactly four columns returned, and that they will be returned in a specific sequence.

    Note that this approach works when a particular field_name is "missing" for a particular ID (it will return a NULL in place of a value). It also works if there are multiple occurrences of the same field_name for a particular ID. (This query will return only one of them, and disregard the other.)

    This same result set can also be obtained with a query written like this:

    SELECT t.id          AS ID
         , f1.sign_up    AS SIGN_UP
         , f2.first_name AS FIRST_NAME
         , f3.street     AS STREET       
      FROM (SELECT s.id
              FROM mytable s
             GROUP BY s.id
             ORDER BY s.id
           ) t
       LEFT      
       JOIN (SELECT s1.id
                  , MIN(s1.value) AS sign_up
               FROM mytable s1
              WHERE s1.field_name = 'sign_up'
                AND s1.value IS NOT NULL 
              GROUP BY s1.id
            ) f1
         ON f1.id = t.id   
       LEFT
       JOIN (SELECT s2.id
                  , MIN(s2.value) AS first_name
               FROM mytable s2
              WHERE s2.field_name = 'first_name'
                AND s2.value IS NOT NULL
              GROUP BY s2.id
            ) f2
         ON f2.id = t.id
       LEFT
       JOIN (SELECT s3.id
                  , MIN(s3.value) AS street
               FROM mytable s3
              WHERE s3.field_name = 'street'
                AND s3.value IS NOT NULL
              GROUP BY s3.id
            ) f3
         ON f3.id = t.id
    

    With other queries, ensure you are getting the desired behavior when a field_name is "missing" for a given ID, or when there are duplicate field_name for a given ID, or when there are additional field_name values in the table which you are not concerned with.

    0 讨论(0)
  • 2020-12-17 03:31

    You can use this simple solution:

    SELECT DISTINCT
        a.id,
        b.value AS SIGN_UP,
        c.value AS FIRST_NAME,
        d.value AS STREET
    FROM tbl a
    LEFT JOIN tbl b ON a.id = b.id AND b.field_name = 'sign_up'
    LEFT JOIN tbl c ON a.id = c.id AND c.field_name = 'first_name'
    LEFT JOIN tbl d ON a.id = d.id AND d.field_name = 'street'
    

    Just to be safe, I made the joins LEFT JOIN's because I do not know if an id can have missing fields, in which case they will show up as NULL in our derived columns.


    SQL-Fiddle Demo

    0 讨论(0)
  • 2020-12-17 03:33

    Am not sure there is a Pivot/Unpivot feature in MySQL. Try this:

    SELECT a.ID, 
           c.FIELD_NAME AS SIGN_UP,
           a.FIELD_NAME AS FIRST_NAME,
           b.FIELD_NAME AS STREET
    
      FROM <YOUR-TABLE> a LEFT JOIN <YOUR-TABLE> b
            ON a.ID = b.ID 
         AND a.FIELD_NAME = 'first_name'
         AND b.FIELD_NAME = 'street' LEFT JOIN <YOUR-TABLE> c
            ON c.ID = a.ID
         AND c.FIELD_NAME = 'sign_up'
    
    0 讨论(0)
提交回复
热议问题