【问题标题】:MS SQL Server : update with less amount of rows in source tableMS SQL Server:更新源表中的行数较少
【发布时间】:2014-11-20 21:49:25
【问题描述】:

如果Table2 的行数少于Table1,用Table2 中的所有值更新Table1 的最佳方法是什么?考虑到Table2 没有可以加入Table1 进行更新的密钥。

TABLE1      TABLE2  RESULT TABLE1
id value    value   id value
----------------------------------------------------
1  NULL     4       1  4
2  NULL     6       2  6
3  NULL     8       3  8
4  NULL             4  4
5  NULL             5  6
6  NULL             6  8
7  NULL             7  4

希望我说得通。

提前致谢。

编辑:对不起,没有指定它的 Microsoft SQL Server 2012。:/

解决方案示例:

DECLARE @t1 TABLE(id int, avalue int)
DECLARE @t2 TABLE(id INT, avalue int)

-- Generate 20 rows in @t1 table
INSERT 
INTO    @t1 (id)
SELECT  Number
FROM    dbo.Numbers 
WHERE   Number BETWEEN 1 AND 20

-- Generate 5 rows and value @t2 table
INSERT 
INTO    @t2 (id,avalue)
SELECT  Number,
        Number
FROM    dbo.Numbers 
WHERE   Number BETWEEN 1 AND 5

-- The goal is to take all rows from @t2
-- and repeatively insert them in order into @t1

UPDATE  t1
SET     t1.avalue = t2.avalue
FROM    @t1 t1 
JOIN    (   SELECT t2.*, COUNT(*) OVER () AS cnt
            FROM @t2 t2
        )   AS t2
ON      (t1.id - 1) % t2.cnt = t2.id - 1;

SELECT  *
FROM    @t1

【问题讨论】:

  • “希望我说得通”不是真的。
  • 该死,也许我应该改进问题。 ://
  • 这是有道理的——他想用第二个表中的value 列依次填充第一个表中的value 列,一遍又一遍。例如:4、6、8、4、6、8等
  • 是的,不好的例子。 Table2 也有 id,1-3。
  • @marc_s 这只是一个意见。除此之外,这里不相关。问题是两个表之间没有关系。 Siyual 似乎在他的理解中是正确的。

标签: sql sql-server sql-server-2012


【解决方案1】:

有趣的问题。第一个解决方案是针对 MySQL 的(我最初读到这个问题是关于那个数据库的)。此解决方案之后是 SQL Server 的解决方案。

您需要生成一个join 密钥。让我假设id 确实是连续的。然后你可以使用模运算来进行匹配:

update table1 t1
       (select (@rn := @rn + 1) as seqnum, value
        from table2 cross join
             (select @rn := -1) vars
       ) t2 cross join
       (select count(*) as cnt from table2) cnt
       on mod((t1.id - 1), cnt.cnt) = t2.seqnum
    set t1.value = t2.value;

如果table1 中的 id 不是连续的,您也可以为此使用变量。它只会使查询更加复杂:

update table1 t1 join
       (select @rn1 := @rn + 1) as seqnum, id
        from table1 t1 cross join
             (select @rn1 := 0) vars
        order by id
       ) t1s
       on t1.id =  t1s.id join
       (select (@rn := @rn + 1) as seqnum, value
        from table2 cross join
             (select @rn := -1) vars
       ) t2 cross join
       (select count(*) as cnt from table2) cnt
       on mod((t1s.seqnum - 1), cnt.cnt) = t2.seqnum
    set t1.value = t2.value;

编辑:

您可以在 SQL Server 中轻松地做同样的事情。其实更简单:

update table1 t1
    set t1.value = t2.value;
    from table1 t1 join
         (select t2.*, count(*) over () as cnt
          from table2 t2
         ) t2
         on (t1.id - 1) % t2.cnt = (t2.id - 1);

这个公式取决于ids 是连续的,没有间隙。放宽这个限制很容易,但是查询变得有点复杂。

【讨论】:

  • @mrw 。 . .我总是忘记 SQL Server 是使用% 还是mod()。由于以下文档,情况变得更糟:msdn.microsoft.com/en-us/library/ee634767.aspx。 SQL Server 系统的组件确实使用mod(),并且它们的文档记录就像数据库也使用一样。
  • 啊,解释一下。 :) 删除了我之前的评论。答案是完美的。非常感谢。
【解决方案2】:

试试这个查询。

DECLARE @Table1  AS TABLE
(
    ID INT,
    Value INT
)

DECLARE @Table2 AS  TABLE
(
    Value INT
)

INSERT INTO @Table1
SELECT 1, NULL UNION
SELECT 2, NULL UNION
SELECT 3, NULL UNION
SELECT 4, NULL UNION
SELECT 5, NULL UNION
SELECT 6, NULL UNION
SELECT 7, NULL 


INSERT INTO @Table2
SELECT 4 UNION
SELECT 6 UNION
SELECT 8 

DECLARE @nCOUNT as INT

SET @nCOUNT = (SELECT COUNT(*) FROM @Table2)

UPDATE TB1 SET TB1.Value = TB2.Value FROM @Table1 AS TB1
INNER JOIN
(SELECT T1.ID, T2.Value FROM 
(SELECT *, CASE WHEN (ROW_NUMBER() OVER(ORDER BY ID) % @nCOUNT) = 0
                THEN @nCOUNT
                ELSE (ROW_NUMBER() OVER(ORDER BY ID) % @nCOUNT)
            END AS ROID
FROM @Table1) AS T1

LEFT JOIN (SELECT VALUE, ROW_NUMBER() OVER(ORDER BY Value) AS ID FROM @Table2) AS T2 ON T2.ID = T1.ROID) AS TB2
ON TB1.ID = TB2.ID

SELECT * FROM @Table1

【讨论】:

    猜你喜欢
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 1970-01-01
    • 2014-03-12
    • 2017-01-27
    相关资源
    最近更新 更多