web-dev-qa-db-ja.com

Azure SQLDWのUPDATEFROM?

UPDATEFROMクエリを実行しようとするとAzureSQLDWでエラーが発生します。エラーは「UPDATEおよびDELETEステートメントのFROM句にサブクエリソースまたは結合を含めることはできません」です。

これはSQLDWに固有のものですか?それ以外の点では、このクエリに問題はありません。 SQL DWの制限である場合、代替手段は何ですか?

-- Permanent fact table with 5 billion rows
CREATE TABLE FactTable (Id1 INT, Id2 INT, EmailAddress NVARCHAR(100), Value1 INT)
WITH (DISTRIBUTION = HASH(EmailAddress));

-- Staging fact table with 10 million rows    
CREATE TABLE StageTable (Id1 INT, Id2 INT, EmailAddress NVARCHAR(100), Value1 INT)
WITH (DISTRIBUTION = HASH(EmailAddress), HEAP);

-- Add a secondary index that should help with joining to StageTable
CREATE NONCLUSTERED INDEX ix ON FactTable (Id1, Id2);

UPDATE fact
SET
   Value1 = CASE WHEN stage.Value1 > fact.Value1 THEN stage.Value1 ELSE fact.Value1 END
FROM FactTable AS fact
INNER JOIN StageTable AS stage ON fact.Id1 = stage.Id1 AND fact.Id2 = stage.Id2
4

ドキュメント に従って、Azure SQL DataWarehouseはUPDATEをサポートしますが、FROM句でのANSI結合はサポートしません。 CTASを使用して回避できます。単純な2テーブルの更新:

UPDATE dbo.FactTable
SET
   Value1 = CASE WHEN stage.Value1 > dbo.FactTable.Value1 THEN stage.Value1 ELSE dbo.FactTable.Value1 END
FROM dbo.StageTable AS stage
WHERE dbo.FactTable.Id1 = stage.Id1 
  AND dbo.FactTable.Id2 = stage.Id2;

CTASを使用したより複雑な例、 メインのUPDATEドキュメントページ から卸売りをコピー:

-- Create an interim table
CREATE TABLE CTAS_acs
WITH (DISTRIBUTION = ROUND_ROBIN)
AS
SELECT  ISNULL(CAST([EnglishProductCategoryName] AS NVARCHAR(50)),0)    AS [EnglishProductCategoryName]
,       ISNULL(CAST([CalendarYear] AS SMALLINT),0)                      AS [CalendarYear]
,       ISNULL(CAST(SUM([SalesAmount]) AS MONEY),0)                     AS [TotalSalesAmount]
FROM    [dbo].[FactInternetSales]       AS s
JOIN    [dbo].[DimDate]                 AS d    ON s.[OrderDateKey]             = d.[DateKey]
JOIN    [dbo].[DimProduct]              AS p    ON s.[ProductKey]               = p.[ProductKey]
JOIN    [dbo].[DimProductSubCategory]   AS u    ON p.[ProductSubcategoryKey]    = u.[ProductSubcategoryKey]
JOIN    [dbo].[DimProductCategory]      AS c    ON u.[ProductCategoryKey]       = c.[ProductCategoryKey]
WHERE   [CalendarYear] = 2004
GROUP BY
        [EnglishProductCategoryName]
,       [CalendarYear]
;

-- Use an implicit join to perform the update
UPDATE  AnnualCategorySales
SET     AnnualCategorySales.TotalSalesAmount = CTAS_ACS.TotalSalesAmount
FROM    CTAS_acs
WHERE   CTAS_acs.[EnglishProductCategoryName] = AnnualCategorySales.[EnglishProductCategoryName]
AND     CTAS_acs.[CalendarYear]               = AnnualCategorySales.[CalendarYear]
;

--Drop the interim table
DROP TABLE CTAS_acs
;
4
wBob

疫病のような大量の更新を避けるために、ASDW(およびAPS/PDW)を使用することをお勧めします。

これは、かなりの割合の行を更新する場合に高速になる純粋なCTASの代替手段です。

Id1は比較的優れた配布キーであり、ステージング行の数はファクト行よりも少ないため、レプリケーションが実行可能であると想定しています。この戦略により、ノード間のデータ移動が排除されます。

非常に大きなステージングテーブルがある場合、各テーブルにid1とid2の組み合わせである代理列を作成し、その列のハッシュによって両方のテーブルを分散すると、パフォーマンスがさらに向上します。

create  table FactTable (
        id1 int,
        id2 int,
        value1 int)
with    (distribution = hash(id1));

create  table StageTable (
        id1 int,
        id2 int,
        value1 int)
with    (distribution = replicate);

create  table UpdatedFact 
with    (distribution = hash(id1)) 
as
select  f.id1,
        f.id2,
        case when s.id1 is not null and s.value1 > f.value1 
            then s.value1
            else f.value1
            end as value1
from    FactTable f
        left outer join StageTable s
        on s.id1 = f.id1
        and s.id2 = f.id2

truncate table FactTable;
alter table UpdatedFact switch to FactTable;
drop table UpdatedFact;
1
Ron Dunn

あなたが試みたことを単純化することはうまくいくでしょう。結合を取り除いて、一方のテーブルをもう一方のテーブルから更新するだけです。

update FactTable
set this = that
from StageTable s where s.something = FactTable.something

これが最善のアプローチであるかどうかは状況によって異なりますが、エラーをスローせずに実行されます。

1
Dan Bracuk