简体   繁体   中英

Select entire row with more than one distinct column

I have a table based on invoice items where I am trying to use SQL to detect at what dates the price or currency for the combination of material/customer has changed. The table contains invoices for several customers although the materials can be common.

My SQL skills are quite basic and I have tried several different approaches using GROUP BY and DISTINCT that I have found in other threads but I always seem to get stuck somewhere along the way.

This is basically what the data looks like:

Invoice Inv. Date   Material    Price   Currency    Per/Qty    Customer
SE100   20140901    111111         1      EUR           1       840006
SE100   20140901    222222         2      EUR         1000      840006
SE100   20140901    333333         3      USD           1       840006
SE101   20140902    111111         1      EUR           1       840006
SE101   20140902    222222         2      EUR         1000      840006
SE101   20140902    333333         3      USD           1       840006
SE102   20140903    111111         2      EUR           1       840006
SE102   20140903    222222         2      USD         1000      840006
SE102   20140903    333333         3      USD           1       840006
SE103   20140904    111111         1      EUR           1       840006
SE103   20140904    222222         2      USD         1000      840006
SE103   20140904    333333         3      USD           1       840006

What I want to accomplish is basically to select the first row datewise for all distinct combinations of Customer/Material/Currency/Price and then subselect the entire rows (sorted by material) for those materials that occur more than once in the selection, thus indicating the price or currency has changed from the initial value.

The expected output from the query using the data in the table above would then look something like this:

Invoice Inv. Date   Material    Price   Currency    Per/Qty    Customer
SE100   20140901    111111         1      EUR           1       840006
SE102   20140903    111111         2      EUR           1       840006
SE103   20140904    111111         1      EUR           1       840006
SE100   20140901    222222         2      EUR         1000      840006
SE102   20140903    222222         2      USD         1000      840006

I hope I managed to explain the problem in an understandable way. The database engine is SQL Server 2005 Express.

Any help would be appreciated...

The key word DISTINCT in SQL has the meaning of "unique value". When applied to a column in a query it will return as many rows from the result set as there are unique, different values for that column. As a consequence it creates a grouped result set, and values of other columns are random unless defined by other functions (such as max, min, average, etc.)

If you meant to say you want to return all rows for which Col 06 has a specific value, then use the " where Col 06 = value " clause

SELECT  mt.*
FROM    (
    SELECT  DISTINCT col6
    FROM    mytable
    ) mto
JOIN    mytable mt
ON      mt.id = 
    (
    SELECT  TOP 1 id
    FROM    mytable mti
    WHERE   mti.col6 = mto.col6
    -- ORDER BY
    --      id
    --  Uncomment the lines above if the order matters
    )

I think this is a direct translation of what you want:

select t.*
from mydata t join
     (select Customer, Material, count(distinct price) as numprices
      from mydata
      group by Customer, Material
      having count(distinct price) > 1
     ) cmcp
     on t.customer = cmcp.customer and t.material = cmcp.material;

This leaves out the currency. Unfortunately, SQL Server doesn't support multiple arguments to distinct . You can include it this way:

select t.*
from mydata t join
     (select Customer, Material,
             count(distinct cast(price as varchar(255)) + ':' + currency) as numprices
      from mydata
      group by Customer, Material
      having count(distinct cast(price as varchar(255)) + ':' + currency)  > 1
     ) cmcp
     on t.customer = cmcp.customer and t.material = cmcp.material;

Most databases support window/analytic functions, so you can also phrase this as:

select t.*
from (select t.*,
             min(cast(price as varchar(255)) + ':' + currency)) over (partition by Customer, Material) as minprice,
             max(cast(price as varchar(255)) + ':' + currency)) over (partition by Customer, Material) as maxprice
      from mydata t
     ) t
where minprice <> maxprice
order by Material, Inv_Date;

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