2016-06-04 13 views
0

Betrachte folgende Tabelle:SQL UPDATE von Gruppen

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TABLE [dbo].[Product](
    [ProductID] [int] IDENTITY(1,1) NOT NULL, 
    [ProductCategory] [int] NOT NULL, 
    [ProductCategoryGuid] [uniqueidentifier] NULL, 
CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED 
(
    [ProductID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
SET IDENTITY_INSERT [dbo].[Product] ON 

GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (1, 2, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (2, 2, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (3, 2, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (4, 3, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (5, 4, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (6, 2, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (7, 3, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (8, 4, NULL) 
GO 
INSERT [dbo].[Product] ([ProductID], [ProductCategory], [ProductCategoryGuid]) VALUES (9, 4, NULL) 
GO 
SET IDENTITY_INSERT [dbo].[Product] OFF 
GO 

Daten sieht wie folgt aus:

ProductID ProductCategory ProductCategoryGuid 
1   2    NULL 
2   2    NULL 
3   2    NULL 
4   3    NULL 
5   4    NULL 
6   2    NULL 
7   3    NULL 
8   4    NULL 
9   4    NULL 

Was ich möchte, ist erreichen, aktualisieren [ProductCategoryGuid] Spalte, so dass alle Zeilen mit demselben Wert für [Product] wird den gleichen GUID-Wert in [ProductCategoryGuid] Spalte

zur Klarstellung:

GUID-Werte werden als Teil der Aktualisierung Abfrage mit NEWID() Funktion

Reihen mit ProduktID IN (1, 2, 3, 6) erzeugt wird GUID1

Reihen mit ProduktID IN hat (4, 7) haben GUID2

Reihen mit ProductID IN (5,8,9) haben GUID3

+0

Dies wäre ein Job, den Sie in der Productcategory-Tabelle ausführen sollten. Wenn Sie keinen haben, erstellen Sie einen. – Solarflare

+0

Es gibt keine ProductCategory-Tabelle. Ich verstehe, dass dies ein bisschen kontraintuitiv ist, aber die eigentliche Aufgabe ist komplizierter und das ist der beste Weg, es für SO zu präsentieren. Ich versuche zu klären: GUID-Werte werden als Teil der Abfrage unter Verwendung von NEWID() Funktion Reihen mit ProduktID IN (1, 2, 3, 6) erzeugt wird GUID1 Reihen mit ProduktID IN hat (4 7) wird, haben GUID2 Reihen mit ProductID IN (5,8,9) wird GUID3 –

+0

Derivative von Bogdan Antwort haben: UPDATE p SET p.ProductCategoryGuid = pc.GD vON dbo.Product p \t INNER JOIN \t (SELECT DISTINCT p2.ProductCategory, NEWID() AS GD \t VON dbo. Produkt p2) AS pc ON p.ProductCategory = pc.ProductKategorie –

Antwort

2

ich folgende Skript verwenden würde, die eine Tabelle Variable Liste der verschiedenen Kategorien zu speichern. Die gleiche Tabellenvariable hat eine GUID-Spalte mit dem Standardwert NEWID(). Am Ende des Skripts gibt es eine UPDATE Anweisung Tabellenvariablen als Quelle und dbo.Product Tabelle als Ziel:

DECLARE @Results TABLE (
    [ProductCategory] [int] NOT NULL, 
    [ProductCategoryGuid] [uniqueidentifier] NOT NULL DEFAULT (NEWID()) 
) 

INSERT @Results (ProductCategory) 
SELECT DISTINCT p.ProductCategory 
FROM dbo.Product p 

UPDATE p 
SET  ProductCategoryGuid = r.ProductCategoryGuid 
OUTPUT deleted.ProductCategoryGuid, inserted.ProductCategoryGuid 
FROM dbo.Product p 
INNER JOIN @Results r ON p.ProductCategory = r.ProductCategory 

Kommentar OUTPUT Klausel, wenn Sie nicht die alten und neuen Werte sehen wollen.

Update: eine Anweisung Lösung (es erfordert SQL2012 +)

;WITH CteUpdateProduct 
AS (
    SELECT *, FIRST_VALUE(NewGUID) OVER(PARTITION BY ProductCategory ORDER BY ProductID) AS NewProductCategoryGuid 
    FROM (
     SELECT p.*, NEWID() AS NewGUID 
     FROM dbo.Product p 
    ) x 
) 
UPDATE CteUpdateProduct 
SET  ProductCategoryGuid = NewProductCategoryGuid 
OUTPUT inserted.ProductID, inserted.ProductCategory, inserted.ProductCategoryGuid; 
+0

Danke, das funktioniert. Jetzt, aus rein akademischen Gründen, bin ich neugierig, ob dies mit einer einzigen Update-Anweisung möglich ist. –

+0

Das Hauptproblem mit einer Anweisungslösung ist, wenn mit diesen Kategorien mit mehreren Zeilen. In diesem Fall "fordert" SQL Server für dieselbe Kategorie zwei oder mehrere zugehörige GUIDs an. Dies bedeutet, dass die Funktion 'NEWID()' für das gleiche category doppelt oder mehr ausgeführt werden kann, was zu diff führt. GUIDs für das gleiche categ. Um diese GUIDs materialisieren zu können könnte die hier beschriebene Lösung verwendet werden: https://stackoverflow.com/questions/13090037/t-sql-cte-materializing-techniques-not-working-on-sql-server2012/13098687#13098687 –

+0

@ JoeSchmoe: siehe zweite Lösung, obwohl jemand argumentieren könnte, ist nicht 100% sicher. –

1
WITH productCategories as (
    SELECT DISTINCT ProductCategory 
    FROM product 
), productCategoriesWithGuid as (
    SELECT ProductCategory, NEWID() ProductCategoryGuid 
    From productCategories 
) 
UPDATE product 
SET ProductCategoryGuid = pc.ProductCategoryGuid 
FROM Product p 
JOIN productCategoriesWithGuid pc on p.ProductCategory = pc.ProductCategory 

Diese Abfrage wird die unterschiedlichen Produktkategorien,

Erstellt eine GUID für jeden von ihnen,

Und schließlich Updates die Produkttabelle mit den GUIDs

Alles in einer Aussage.

+0

Diese Lösung wurde getestet? Die Hauptfrage ist, wie oft der innere Teil von JOIN ausgewertet wird, wenn es zwei oder mehr Zeilen mit demselben Category gibt? –

+0

Dies funktioniert nicht für mich. Es erzeugt eine eindeutige Guid für jede Zeile. –

+0

Das ist komisch. Kann nicht herausfinden warum. Will hineinschauen. – PeterO