可以从其他条目

时间:2018-04-24 16:10:43

标签: sql

我有一张表,其中有些条目未正确填写。目前,我无法修复表格的填充方式,因此对于我的Select语句,我需要解决这个问题。这是它的样子:

Name  | Address  | Value | Date
--------------------------------
Peter | New York | 10    | 03-26-18
Peter |          | 20    | 03-27-18
Peter | Chicago  | 15    | 03-28-18

在样本中,我需要用下一个日期的地址值填充缺失的地址,例如芝加哥。最终输出应如下所示:

Name  | Address  | Value | Date
--------------------------------
Peter | New York | 10    | 03-26-18
Peter | Chicago  | 20    | 03-27-18
Peter | Chicago  | 15    | 03-28-18

有一个边缘情况,在同一日期可能有两个同名的条目。在这种情况下,任何一个条目都可以选择作为地址。如果这不起作用,那也没关系,一个不包括边缘案例的解决方案已经帮助我,因为我的所有尝试都导致了重复的条目。

谢谢!

3 个答案:

答案 0 :(得分:0)

试试这个:

UPDATE A
SET A.Address=B.Address
FROM TABLE_NAME A 
JOIN TABLE_NAME B
ON A.NAME=B.NAME AND A.DATE=DATEADD(DD, -1, B.DATE) 
WHERE A.Address IS NULL;

查看有效的DEMO on SQL Fiddle

答案 1 :(得分:0)

假设您选择的表格中存在某种ID,您可以使用LEFT JOIN表格自行执行此操作,并根据{{1}选择下一条记录的条件当Date列为null或为空时,仅使用联接结果。这应该处理您的边缘情况和非连续日期。 (将Address替换为您的表名)

test

答案 2 :(得分:0)

好的,我重写了原始查询。我没有考虑到多个缺失值,因为您的原始表没有多个缺失,但我首先应该考虑到这一点。这应该是你正在寻找的。希望它有所帮助。

表:

CREATE TABLE [dbo].[Persons](
    ID int IDENTITY(1,1) PRIMARY KEY,
    [Name] [varchar](255) NULL,
    [Address] [varchar](255) NULL,
    [Date] [datetime] NULL
) ON [PRIMARY]

INSERT INTO Persons (Name, Address, Date)
VALUES
('Peter', 'New York', '2018-03-26'),
('Peter',  NULL, '2018-03-27'),
('Peter', 'Chicago', '2018-03-28'),
('Peter',  NULL, '2018-03-29'),
('Peter',  NULL, '2018-03-31'),
('Peter',  NULL, '2018-04-01'),
('Peter',  NULL, '2018-04-02'),
('Peter',  NULL, '2018-04-03'),
('Peter', 'Michigan', '2018-04-04')

GO

<强>查询:

WITH CTE1(Name, Address, Date, DateRank) AS (
SELECT Name, Address, Date, RANK() OVER (PARTITION BY Name ORDER BY Date ASC) AS DateRank FROM Persons
),

CTE2(Name, Address, Date, DateRank) AS (
SELECT Name, Address, Date, DateRank FROM CTE1 WHERE Address IS NOT NULL
)

SELECT 
    x.Name, 
    x.Address,
        CASE WHEN z.DateRank IS NULL 
            THEN COALESCE((SELECT TOP(1) ADDRESS FROM CTE2 WHERE x.DateRank < CTE2.daterank), 'NA')
            ELSE z.Address      
        END AS CombinedAddress,
    x.Date
FROM CTE1 x
LEFT JOIN CTE2 z ON x.DateRank = z.DateRank
ORDER BY x.Date ASC

<强>结果:

Name | Address | CombinedAddress | Date
----------------------------------------
Peter   New York    New York    2018-03-26 
Peter   NULL        Chicago     2018-03-27 
Peter   Chicago     Chicago     2018-03-28 
Peter   NULL        Michigan    2018-03-29 
Peter   NULL        Michigan    2018-03-31 
Peter   NULL        Michigan    2018-04-01 
Peter   NULL        Michigan    2018-04-02 
Peter   NULL        Michigan    2018-04-03 
Peter   Michigan    Michigan    2018-04-04 

旧答案

就我个人而言,我喜欢Rank功能。将CTE与Rank()结合使用可以为以后的格式化提供大量精细控制。这就是我提出的。希望它有所帮助。

表:

CREATE TABLE [dbo].[Persons](
    [Id] [int] NULL,
    [Name] [varchar](255) NULL,
    [Address] [varchar](255) NULL,
    [Date] [datetime] NULL
) ON [PRIMARY]

INSERT INTO Persons (Id, Name, Address, Date)
VALUES
(1, 'Peter', 'New York', '2018-03-26'),
(2, 'Peter', 'NULL', '2018-03-27'),
(3, 'Peter', 'Chicago', '2018-03-28'),
(4, 'Peter', 'NULL', '2018-03-29'),
(5, 'Peter', 'Michigan', '2018-03-31')

GO

查询:

WITH CTE1(Name, Address, Date, DateRank) AS (
SELECT Name, Address, Date, RANK() OVER (PARTITION BY Name ORDER BY Date DESC) AS DateRank FROM Persons
), 

CTE2(Name, Address, Date, DateRank) AS (
SELECT Name, Address, Date, RANK() OVER (PARTITION BY Name ORDER BY Date DESC) + 1 AS DateRank FROM Persons
),

Query(Name, Address, Date, CombinedAddress) AS (
    Select x.Name, 
    x.Address, 
    x.Date,
    Address = CASE
        WHEN x.DateRank % 2 = 0 THEN COALESCE(z.Address, 'NA')
        ELSE COALESCE(x.Address, 'NA')
        END
FROM CTE1 x
LEFT JOIN CTE2 z ON x.DateRank = z.DateRank
)

SELECT * FROM Query ORDER BY Date ASC