Copying values from another row

2019-07-12 16:38发布

问题:

I have a table that looks like this:

  ID               AMID           DESC                  value 
  -----------------------------------------------------------------
  100              type A         AMID type A             10
  101              type B         AMID type B             18
  102              type C         AMID type C             34
  101               null            null                   4
  102               null            null                  19
  103              type D         AMID type D              6   
  103              type E            null                  7 

The table contains around 6 million rows.

Now I want to have the result like this

  ID               AMID           DESC                  value 
  -------------------------------------------------------------
  100              type A         AMID type A             10
  101              type B         AMID type B             18
  102              type C         AMID type C             34
  101              type B         AMID type B              4
  102              type C         AMID type C             19
  103              type D         AMID type D              6   
  103              type E            null                  7

It has show the same values when the AMID for ID in both rows are equal are one of it is null, if the AMID is different then leave it like that..

Thanks in advance for the help..

Cheers,

Harish

回答1:

First, let's set up some proper DDL and sample data:

USE tempdb;
GO

CREATE TABLE dbo.AMID
(
  ID     INT, 
  AMID   VARCHAR(32), 
  [DESC] VARCHAR(32), 
  value  INT
);

INSERT dbo.AMID SELECT 100, 'type A', 'AMID type A', 10
      UNION ALL SELECT 101, 'type B', 'AMID type B', 18
      UNION ALL SELECT 102, 'type C', 'AMID type C', 34
      UNION ALL SELECT 101,  null   , null         , 4
      UNION ALL SELECT 102,  null   , null         , 19
      UNION ALL SELECT 103, 'type D', 'AMID type D', 6   
      UNION ALL SELECT 103, 'type E', null         , 7;

Instead of using TOP without ORDER BY, which I don't even know what it means, you can pick exactly one row to use for populating the NULL rows using partition + order. In your limited sample data you only have a max of two rows for any ID, but in case you can have more, this is important (otherwise, like TOP without ORDER BY, you're going to pull some arbitrary row, making your update less than predictable). This orders by the value in the AMID column, but you can change this to pick the top row per ID using any criteria in the table.

;WITH src AS 
(
  SELECT ID, AMID, [DESC]
  FROM dbo.AMID 
  WHERE AMID IS NULL AND [DESC] IS NULL
),
nv AS 
(
  SELECT ID, AMID, [DESC], rn = ROW_NUMBER() OVER
  (PARTITION BY ID ORDER BY AMID) -- change this ordering accordingly
  FROM dbo.AMID 
  WHERE AMID IS NOT NULL
)
UPDATE src
  SET AMID = nv.AMID, [DESC] = COALESCE(nv.[DESC], src.[DESC])
FROM src INNER JOIN nv
ON src.ID = nv.ID
WHERE nv.rn = 1;

SELECT ID, AMID, [DESC], Value FROM dbo.AMID;

Results:

ID   AMID    DESC         value
---  ------  -----------  -----
100  type A  AMID type A  10
101  type B  AMID type B  18
102  type C  AMID type C  34
101  type B  AMID type B  4
102  type C  AMID type C  19
103  type D  AMID type D  6
103  type E  NULL         7     

Don't forget to clean up:

DROP TABLE dbo.AMID;
GO

As an aside, DESC is a horrible name for a column, since it's a T-SQL keyword, and therefore always has to be escaped with [double quotes].



回答2:

If i've understood your requirement correctly:

SELECT ID
,      COALESCE(AMID, (
           SELECT TOP 1 AMID FROM Table t2 WHERE t2.ID=ID AND t2.AMID IS NOT NULL
       ))AS AMID
,      DESC                  
,      value  
FROM Table

COALESCE (Transact-SQL)



回答3:

select a1.ID,
ISNULL(a1.amid, a3.amid),
a1.[DESC],
a1.value
FROM amid a1
LEFT OUTER JOIN (select a2.id, amid = max(a2.amid)
    from amid a2
    where  a2.amid is not null
    group by a2.id) a3 on a3.id = a1.id

Not clear from your question what version of SQL you're using but the above should work on anything from SQL2000 up.

Basically you can tweak the query in the derived table to get the results you prefer.