SQL Server: CTE WHILE LOOP назначает одно и то же значение переменной - PullRequest
1 голос
/ 28 июня 2019

У меня есть таблица prd0101 с этими данными:

codi        descr               nomfam                  nomsub          nomgru      marc    codf                peso    estado  fe_i
---------------------------------------------------------------------------------------------------------------------------------------------------------
0301-011611 TIRAS DE PRUEBA     PRODUCTOS TERMINADOS    ALIGERADOS      ALIGERADOS  ND      123456789ABCDEF     0.0250  1       2019-06-27 00:00:00.000
0301-011612 TIRAS PRUEBAS 2     PRODUCTOS TERMINADOS    ALIGERADOS      ALIGERADOS  ND      123456789ABCDE1     0.0360  1       2019-06-27 00:00:00.000
0301-011613 TIRAS PRUEBA 3      PRODUCTOS TERMINADOS    ALIGERADOS      ALIGERADOS  ND      123456789ABCDEF2    0.0690  1       2019-06-27 00:00:00.000

И это мой запрос, чтобы выбрать данные и вставить их в другую таблицу с именем product2:

DECLARE 
     @COUNTER INT = 0 ,
     @MAX INT = (SELECT COUNT(*)
                 FROM prd0101 p 
                 LEFT JOIN tbl01itm i ON p.codi = i.codi
                 LEFT JOIN tbl01grp g ON g.codgru = i.codgru
                 LEFT JOIN tbl01sbf s ON s.codsub = g.codsub
                 LEFT JOIN tbl01fam f ON f.codfam = s.codfam
                 WHERE p.fe_i >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)),
     @CODI NVARCHAR(100), 
     @DESCR NVARCHAR(100), 
     @NOMFAM NVARCHAR(100),
     @NOMSUB NVARCHAR(100), 
     @NOMGRU NVARCHAR(100), 
     @MARC NVARCHAR(100), 
     @CODF NVARCHAR(100),
     @PESO NVARCHAR(100), 
     @ESTADO NVARCHAR(100)


WHILE @COUNTER < @MAX
BEGIN
    --cte
    ;WITH cte AS
    (
        SELECT   
            p.codi, p.descr, f.nomfam, s.nomsub,
            g.nomgru, p.marc, p.codf, p.peso, p.estado, p.fe_i
        FROM 
            prd0101 p 
        LEFT JOIN
            tbl01itm i ON p.codi = i.codi
        LEFT JOIN
            tbl01grp g ON g.codgru = i.codgru
        LEFT JOIN
            tbl01sbf s ON s.codsub = g.codsub
        LEFT JOIN
            tbl01fam f ON f.codfam = s.codfam
    )
    SELECT 
        @CODI = cte.codi, @DESCR = cte.descr, 
        @NOMFAM = cte.nomfam, @NOMSUB = cte.nomsub, 
        @NOMGRU = cte.nomgru, @MARC = cte.marc, 
        @CODF = cte.codf, @PESO = cte.peso, @ESTADO = cte.estado
    FROM 
        cte
    WHERE 
        cte.fe_i >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)
        AND cte.estado = 1

    IF NOT EXISTS (SELECT codi FROM Product2 WHERE codi = @CODI)
    BEGIN
        INSERT INTO Product2 (codi, "Description", Familia__c, Subfamilia__c, Grupo__c, Marca__c, ProductCode, Peso__c, IsActive)
        VALUES (@CODI, @DESCR, @NOMFAM, @NOMSUB, @NOMGRU, @MARC, @CODF, @PESO, @ESTADO)
    END

    SET @COUNTER = @COUNTER + 1
END

Проблема в том, что в цикле всегда назначается одна и та же запись. Запись с кодом = 0301-011613

Я печатаю некоторую переменную внутри цикла, и она выводит ту же последнюю строку для трех из них.

Я ожидаю вставить 3 записи, но будет вставлена ​​только последняя.

Ответы [ 2 ]

0 голосов
/ 28 июня 2019

Я исправил это, добавив это к cte select:

ROW_NUMBER() OVER(ORDER BY p.codi) AS 'Row1'

и за пределами cte после предложения WHERE я добавил это:

AND Row1 = @COUNTER + 1

, который повторяет всю строку, как я ожидал.

0 голосов
/ 28 июня 2019

Исходный TSQL (с CTE), похоже, возвращает одинаковое значение для каждого цикла (последняя запись в наборе результатов?). То есть скалярная переменная @COUNTER увеличивается до тех пор, пока она не превысит @MAX, но оператор CTE / SELECT, похоже, не меняет того, что возвращает.

Похоже, что вы хотите вставить товары текущего дня (независимо от времени) в таблицу Product2, но только когда estado = 1 и только если код еще не существует в таблице Product2.

Если это так и предполагается, что codi содержит уникальные значения, вы можете сделать это с помощью оператора INSERT:

INSERT Product2(codi
                ,Description
                ,Familia__c
                ,Subfamilia__c
                ,Grupo__c
                ,Marca__c
                ,ProductCode
                ,Peso__c
                ,IsActive
               )

SELECT      p.codi
            ,p.descr
            ,f.nomfam
            ,s.nomsub
            ,g.nomgru
            ,p.marc
            ,p.codf
            ,p.peso
            ,p.estado

  FROM      prd0101 AS p

            LEFT JOIN tbl01itm AS i 
            ON p.codi=i.codi

            LEFT JOIN tbl01grp AS g 
            ON g.codgru=i.codgru

            LEFT JOIN tbl01sbf AS s 
            ON s.codsub=g.codsub

            LEFT JOIN tbl01fam AS f 
            ON f.codfam=s.codfam

 WHERE      -- Note: Select all rows from current day, regardless of time:
            p.fe_i >= DATEADD(DAY,DATEDIFF(DAY,0,GETDATE()),0)
   AND      p.estado = 1
   AND      NOT EXISTS 
            (SELECT P2.codi 
               FROM Product2 AS P2
              WHERE p2.codi = p.codi
            )
;


SELECT      *

  FROM      Product2
;

Вывод показывает три строки, как и ожидалось:

|        codi |     Description | Familia__c | Subfamilia__c | Grupo__c | Marca__c |      ProductCode | Peso__c | IsActive |
|-------------|-----------------|------------|---------------|----------|----------|------------------|---------|----------|
| 0301-011611 | TIRAS DE PRUEBA |          1 |             1 |        1 |       ND |  123456789ABCDEF |       0 |        1 |
| 0301-011612 | TIRAS PRUEBAS 2 |          1 |             1 |        1 |       ND |  123456789ABCDE1 |       0 |        1 |
| 0301-011613 |  TIRAS PRUEBA 3 |          1 |             1 |        1 |       ND | 123456789ABCDEF2 |       0 |        1 |

SQL Fiddle (ссылки на другие таблицы закомментированы, поскольку данные не предоставлены; также я заменил GETDATE () на дату '2019-06-27', чтобы соответствовать предоставленным данным): http://sqlfiddle.com/#!18/5ba09/18

...