web-dev-qa-db-ja.com

SQLの列の値に行の値が存在する価格を更新するにはどうすればよいですか?

列p1を更新したいのですが、p1は同じ製品です。

列p1を更新します。ここで、C1の例g6-1seは列名に存在し、行g6-1seの列p1の値nullを行g6-1srの値p1で更新します。

行1で、g6-1を読み取り、列名を検索し、存在する場合は列p1を更新します。 g6-1srを読み取って検索した後、行1の列c1の終了行に到達するまで、次にポインター、更新前の行をポイントして、列p1をnullにしません。

更新前のtbl:

    +-------+-------------+-----------------------------------------------+-------+
    | id    | Name        | C1                                            | P1    |
    +-------+-------------+-----------------------------------------------+-------+
    | 29214 | g6-1sr      | g6-1, g6-1sr, g6-1se,g6-1se12,g6-1se1         | 28000 |
    | 29215 | g6-1se      | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29226 | g6-1sf      | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29237 | g6-1se1     | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29248 | g6-1se12    | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29259 | Nkg6-1se    | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29269 | N56-1341se  | N56-11, N56-1341se, N56-1100, N56-1348se,     | 32000 |
    | 29270 | N56-1348se  | N56-11, N56-21, N56-1100, N56-2980,           | null  |
    | 29271 | F566 1341se | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | 38000 |
    +-------+-------------+-----------------------------------------------+-------+

更新後のtbl:

    +-------+-------------+-----------------------------------------------+-------+
    | id    | Name        | C1                                            | P1    |
    +-------+-------------+-----------------------------------------------+-------+
    | 29214 | g6-1sr      | g6-1, g6-1sr, g6-1se,g6-1se12,g6-1se1         | 28000 |
    | 29215 | g6-1se      | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | 28000 |
    | 29226 | g6-1sf      | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29237 | g6-1se1     | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | 28000 |
    | 29248 | g6-1se12    | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | 28000 |
    | 29259 | Nkg6-1se    | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | null  |
    | 29269 | N56-1341se  | N56-11, N56-1341se, N56-1100, N56-1348se,     | 32000 |
    | 29270 | Asus N56-1348se  | N56-11, N56-21, N56-1100, N56-2980, N56-2| 32000 |
    | 29271 | F566 1341se | g6-1, g6-2, g6-1000, g6-1980,       g6-1230,  | 38000 |
    +-------+-------------+-----------------------------------------------+-------+

カーソルで試してみてくださいが成功しません

1
RedArmy

チェックしてください:dbfiddle ここ

基本的に、P1がnullであるすべての行を取得し、P1値を持ち、名前がc1のようなすべての行と結合します。

LIKEの使用

UPDATE     t1 
SET        P1 = t2.P1
FROM       tbl1 t1
INNER JOIN tbl1 t2 
ON         t2.P1 IS NOT NULL 
AND        t2.c1 LIKE '%' + t1.Name + '%'
WHERE      t1.P1 IS NULL;

|   id|Name       |C1                                          |   P1|
|----:|:----------|:-------------------------------------------|----:|
|29214|g6-1sr     |g6-1, g6-1sr, g6-1se,g6-1se12,g6-1se1       |28000|
|29215|g6-1se     |g6-1, g6-2, g6-1000, g6-1980,       g6-1230,|28000|
|29226|g6-1sf     |g6-1, g6-2, g6-1000, g6-1980,       g6-1230,|     |
|29237|g6-1se1    |g6-1, g6-2, g6-1000, g6-1980,       g6-1230,|28000|
|29248|g6-1se12   |g6-1, g6-2, g6-1000, g6-1980,       g6-1230,|28000|
|29259|Nkg6-1se   |g6-1, g6-2, g6-1000, g6-1980,       g6-1230,|     |
|29269|N56-1341se |N56-11, N56-1341se, N56-1100, N56-1348se,   |32000|
|29270|N56-1348se |N56-11, N56-21, N56-1100, N56-2980,         |32000|
|29271|F566 1341se|g6-1, g6-2, g6-1000, g6-1980,       g6-1230,|38000|

dbo.SplitCompare()関数の使用

UPDATE     t1 
SET        P1 = t2.P1
FROM       tbl1 t1
INNER JOIN tbl1 t2 
ON         t2.P1 IS NOT NULL 
AND        dbo.SplitCompare(t2.C1, t1.Name) = 1
WHERE      t1.P1 IS NULL;

更新

チェックしてください:dbfiddle ここ

まず、新しい関数を追加しました:[dbo]。[SplitCompare]

-------------------------------------------------------------------------------------
-- Compares each item of a coma-delimited string (without trainling spaces), 
-- against @ToSearch.
--
-- Returns: (int)
--
--    1 - @ToSearch matches some item
--    0 - No matches found.
-------------------------------------------------------------------------------------
CREATE FUNCTION [dbo].[SplitCompare] (@List nvarchar(MAX), @ToSearch nvarchar(1024))
RETURNS int
AS
BEGIN
    DECLARE @Item nvarchar(1024) = null;
    DECLARE @Result int = 0;

    WHILE LEN(@List) > 0
    BEGIN
        IF PATINDEX('%,%', @List) > 0
        BEGIN
            SET @Item = SUBSTRING(@List, 0, PATINDEX('%,%', @List));
            SET @List = SUBSTRING(@List, LEN(@Item + ';') + 1, LEN(@List));
        END
        ELSE
        BEGIN
            SET @Item = @List;
            SET @List = NULL;
         END

    IF RTRIM(LTRIM(@Item)) = @ToSearch -- does it match?
    BEGIN
        SET @Result = 1;
        SET @List = '';
    END
    END

    RETURN @Result;

END

次に、OP要件に従って、CURSORを使用してこのソリューションを実装しました。

-------------------------------------------------------------------------------------
-- Use @LimitRows just to limit the number of rows to be updated each time 
-- the script is executed.
-------------------------------------------------------------------------------------
DECLARE @LimitRows int = 100;
DECLARE @Id int, @Name nvarchar(2048), @P1 int;

-- only selects rows where P1 IS NULL
DECLARE CurPrices CURSOR
    FOR SELECT TOP (@LimitRows) Id, Name FROM #tbl1 WHERE P1 IS NULL;

OPEN CurPrices 
FETCH NEXT FROM CurPrices INTO @Id, @Name

WHILE @@FETCH_STATUS = 0  
BEGIN

    SET @P1 = NULL;

    -- note: top (1)
    --
    SELECT   TOP (1) @P1 = t.P1
    FROM     tbl1 t
    WHERE    t.P1 IS NOT NULL
    AND      dbo.SplitCompare(t.C1, @Name) = 1
    ORDER BY Id;

    IF COALESCE(@P1,0) > 0
    BEGIN
        UPDATE #tbl1
        SET    P1 = @P1
        WHERE  Id = @Id;

        IF @@ERROR <> 0
        BEGIN
           CLOSE CurPrices;
           DEALLOCATE CurPrices;
           RAISERROR('ERROR', 20, -1);
        END
    END

    FETCH NEXT FROM CurPrices INTO @Id, @Name    
END

CLOSE CurPrices;
DEALLOCATE CurPrices;

結果は最初のコマンドと同じですが、これにより、実行されるたびに影響を受ける行の数を制限できます。

3
McNets