1

如果我有这些数据的行:

ID |Name        |ContractType|
---|------------|------------|
 1 |Aaron Shatz | 6-month    |
 2 |Jim Smith   |12-month    |
 3 |Jim Smith   | 6-month    |
 4 |Mark Johnson|12-month    |

我不能使用 Id 来确定要使用的记录:我必须使用ContractType。我想从一个表中选择所有记录,但是如果存在具有相同名称值的记录,我想选择12 个月的合同记录。

查询的结果应该是:

ID |Name        |ContractType|
---|------------|------------|
 1 |Aaron Shatz | 6-month    |
 2 |Jim Smith   |12-month    |
 4 |Mark Johnson|12-month    |
4

2 回答 2

5

硬编码版本

该解决方案假设只有两种合同类型,即 6 个月和 12 个月。请滚动到底部查看dynamic版本。

单击此处查看 SQL Fiddle 中的演示。

脚本

CREATE TABLE contracts
(
        id              INT         NOT NULL IDENTITY
    ,   name            VARCHAR(30) NOT NULL
    ,   contracttype    VARCHAR(30) NOT NULL
);

INSERT INTO contracts (name, contracttype) VALUES
    ('Aaron Shatz',     '6-month'),
    ('Jim Smith',       '12-month'),
    ('Jim Smith',       '12-month'),
    ('Mark Johnson',    '12-month'),
    ('John Doe',        '6-month'),
    ('Mark Johnson',    '6-month'),
    ('Aaron Shatz',     '6-month');

SELECT id   
    ,   name
    ,   contracttype
FROM
(
    SELECT  id  
        ,   name
        ,   contracttype
        ,   ROW_NUMBER() OVER(PARTITION BY name ORDER BY contracttype) AS rownum
    FROM    contracts
) T1 
WHERE rownum = 1
ORDER BY id;

输出

id  name          contracttype
--  ------------  ------------
1   Aaron Shatz   6-month
2   Jim Smith     12-month
4   Mark Johnson  12-month
5   John Doe      6-month

动态版

这会将合同类型数据移动到它自己的带有序列列的表中。根据合同类型的排序方式,查询将获取适当的记录。

单击此处查看 SQL Fiddle 中的演示。

脚本

CREATE TABLE contracts
(
        id              INT         NOT NULL IDENTITY
    ,   name            VARCHAR(30) NOT NULL
    ,   contracttypeid  INT         NOT NULL
);

CREATE TABLE contracttypes 
(
        id              INT         NOT NULL IDENTITY
    ,   contracttype    VARCHAR(30) NOT NULL
    ,   sequence        INT         NOT NULL 
)

INSERT INTO contracttypes (contracttype, sequence) VALUES
    ('12-month', 1),
    ('6-month',  3),
    ('15-month',  2);

INSERT INTO contracts (name, contracttypeid) VALUES
    ('Aaron Shatz',     2),
    ('Jim Smith',       2),
    ('Jim Smith',       3),
    ('Mark Johnson',    1),
    ('John Doe',        2),
    ('Mark Johnson',    2),
    ('Aaron Shatz',     2);

SELECT  id  
    ,   name
    ,   contracttype
FROM
(
    SELECT  c.id    
        ,   c.name
        ,   ct.contracttype
        ,   ROW_NUMBER() OVER(PARTITION BY name ORDER BY ct.sequence) AS rownum
    FROM            contracts           c
    LEFT OUTER JOIN contracttypes       ct
    ON              c.contracttypeid    = ct.id
) T1 
WHERE rownum = 1
ORDER BY id;

输出

id  name          contracttype
--  ------------  ------------
1   Aaron Shatz   6-month
3   Jim Smith     15-month
4   Mark Johnson  12-month
5   John Doe      6-month
于 2012-04-30T21:24:20.567 回答
4

是因为 OP 已确认只有两种合同类型是可能的,而他想要的(对于每个承包商)恰好是按字母顺序排列的第一个。因此,一些巧合使这个解决方案变得直截了当。

;WITH x AS
(
  SELECT ID, Name, ContractType, rn = ROW_NUMBER() OVER
    (PARTITION BY Name ORDER BY ContractType)
  FROM dbo.some_table
)
SELECT ID, Name, ContractType 
  FROM x
  WHERE rn = 1
  ORDER BY ID;

如果您需要使其更具动态性,我想您可以说:

DECLARE @PreferredContractType VARCHAR(32);
SET @PreferredContractType = '12-month';

;WITH x AS
(
  SELECT ID, Name, ContractType, rn = ROW_NUMBER() OVER
    (PARTITION BY Name ORDER BY CASE ContractType
      WHEN @PreferredContractType THEN 1 ELSE 2 END
    )
  FROM dbo.some_table
)
SELECT ID, Name, ContractType 
  FROM x
  WHERE rn = 1
  ORDER BY ID;
于 2012-04-30T21:18:51.573 回答