选择可能具有相同值的行的多个实例

Posted

技术标签:

【中文标题】选择可能具有相同值的行的多个实例【英文标题】:SELECT multiple instances of a row where they might have the same value 【发布时间】:2020-10-15 13:43:59 【问题描述】:

我希望能够选择一些客户详细信息,然后选择客户地址详细信息,现在这些客户地址详细信息还包括以前的地址,有些客户最多有 3 个地址(包括以前的),有些只有一个。

我想从客户数据库中选择客户,然后从地址数据库中选择客户地址,并在同一行上为每个客户加载最多 3 个地址。

客户数据库:

   |   name  |   value    |   num |SecondName|    Date      |  
   | James   |   HEX124   |   1   |  Carl    |   11022020   |  
   | Jack    |   JEU836   |   4   |  Smith   |   19042020   |   
   | Mandy   |   GER234   |   33  |  Jones   |   09042020   |

地址数据库

   |   Address            |   value    | PostCode  |  
   |   1 Smith street     |   HEX124   |  LN18HB   |      
   |   12 fellow garden   |   GER234   |  LN18JL   |   
   |   8 Long street      |   HEX124   |  FF23F2   |      
   |   8 Big road         |   HEX124   |  FWF4GW   |      
   |   89 Kings avenue    |   GER234   |  HH29DD   |   
   |   Roadhouse Cottage  |   JEU836   |  FK28DD   |   

客户数据库中的“值”列是客户的唯一值,该值也用于地址数据库中,最多可为该特定客户分配 3 个地址

下面是我的 SQL:

SELECT c.name, c.value, c.num, c.secondname, c.date,
 a.address, a.value, a.postcode,
 a2.address, a2.value, a2.postcode,
 a3.address, a3.value, a3.postcode 
FROM Customers c

INNER JOIN Address a ON a.value = c.value.     //first address
INNER JOIN Address a2 ON a2.value = c.value    //second address
INNER JOIN Address a3 ON a3.value = c.value    //third address

这将为每个客户返回尽可能多的行,与他们拥有的地址一样多,并将为他们重复相同的地址 3 次:

结果:

   | James   |   HEX124   |   1   |  Carl    |   11022020  |   1 Smith street     |   HEX124   |  LN18HB      |   1 Smith street     |   HEX124   |  LN18HB    |   1 Smith street     |   HEX124   |  LN18HB   |      
   | James   |   HEX124   |   1   |  Carl    |   11022020  |   8 Long street      |   HEX124   |  FF23F2        |   8 Long street      |   HEX124   |  FF23F2   |   8 Long street      |   HEX124   |  FF23F2   |      

如您所见,上面的结果只是为客户重复相同的地址,James 将有 3 行,Mandy 2 行,Jack 1 行(每个地址 1 行)

所以我尝试添加它,希望它会读取不同的地址,或者如果它们没有 3 个地址,则返回空值:

WHERE a.address <> a2.address   //Saying the addresses must not be the same, but this loads nothing when I run the SQL
AND   a.address <> a3.address
AND   a2.address <> a3.address

但这会返回 0 个结果

想要的结果:

   | James   |   HEX124   |   1   |  Carl    |   11022020     |   1 Smith street     |   HEX124   |  LN18HB    |   8 Long street      |   HEX124   |  FF23F2   |   8 Big road         |   HEX124   |  FWF4GW   |    
   | Jack    |   JEU836   |   4   |  Smith   |   19042020     |   Roadhouse Cottage  |   JEU836   |  FK28DD    |   
   | Mandy   |   GER234   |   33  |  Jones   |   09042020     |   12 fellow garden   |   GER234   |  LN18JL    |   89 Kings avenue    |   GER234   |  HH29DD   |   

正如您在我想要的结果中看到的那样,我将每个客户加载一次,他们以前的所有地址都放在他们列的末尾,一些客户将有 1、2 或 3 个地址,

【问题讨论】:

如果有 4 个(或更多)地址,什么决定应该返回哪 3 个地址? 【参考方案1】:

似乎你在这里追求的是一个支点,但在 ROW_NUMBER 的值上。我假设您有某种始终升序的地址键,因此您可以确定最近的地址。我还使用了交叉表(条件聚合),因为它比 PIVOT 运算符的限制要小得多:

WITH RNs AS(
    SELECT c.[name],
           c.[value],
           c.num,
           c.secondname,
           c.[date],
           a.address,
           a.[value] AS addressvalue,
           a.postcode,
           ROW_NUMBER() OVER (PARTITION BY c.[value] ORDER BY a.idcolumn DESC) AS RN
    FROM dbo.Customer c
         JOIN dbo.Address a ON a.[value] = c.[value])
SELECT R.[name],
       R.[value],
       R.num,
       R.secondname,
       R.[date],
       MAX(CASE R.RN WHEN 1 THEN R.address END) AS address1,
       MAX(CASE R.RN WHEN 1 THEN R.addressvalue END) AS addressvalue1,
       MAX(CASE R.RN WHEN 1 THEN R.postcode END) AS postcode1,
       MAX(CASE R.RN WHEN 2 THEN R.address END) AS address2,
       MAX(CASE R.RN WHEN 2 THEN R.addressvalue END) AS addressvalue2,
       MAX(CASE R.RN WHEN 2 THEN R.postcode END) AS postcode2,
       MAX(CASE R.RN WHEN 3 THEN R.address END) AS address3,
       MAX(CASE R.RN WHEN 3 THEN R.addressvalue END) AS addressvalue3,
       MAX(CASE R.RN WHEN 3 THEN R.postcode END) AS postcode3       
FROM RNs R
GROUP BY c.[name],
         c.[value],
         c.num,
         c.secondname,
         c.[date];

【讨论】:

【参考方案2】:
You can utilize Row_Number(). ie:


with addresses (AddrNo, [Value], Address, PostCode) as
(
  Select row_number() over (partition by [value] order by Address, PostCode),
     [Value], Address, PostCode
)
SELECT c.name, c.value, c.num, c.secondname, c.date,
 max(case when a.AddrNo=1 then a.address end) as Address1, 
 max(case when a.AddrNo=1 then a.[Value] end) as Value1, 
 max(case when a.AddrNo=1 then a.PostCode end) as PostCode1, 
 max(case when a.AddrNo=2 then a.address end) as Address2, 
 max(case when a.AddrNo=2 then a.[Value] end) as Value2, 
 max(case when a.AddrNo=2 then a.PostCode end) as PostCode2, 
 max(case when a.AddrNo=3 then a.address end) as Address3, 
 max(case when a.AddrNo=3 then a.[Value] end) as Value3, 
 max(case when a.AddrNo=3 then a.PostCode end) as PostCode3 
FROM Customers c
INNER JOIN Addresses a ON a.[value] = c.[value]
group by c.name, c.value, c.num, c.secondname, c.date;

注意:这只是其中一种方法。还有其他方法可能更容易。

【讨论】:

以上是关于选择可能具有相同值的行的多个实例的主要内容,如果未能解决你的问题,请参考以下文章

SQLITE3 - 删除具有相同值的多个列的行

聚合具有两个或多个具有相同值的列的行

用SQL拆分具有多个值的行

选择具有相同值的上次更新的行

选择具有多个重复字段值的行

SQL - 选择两列中具有相同值的行