2016-04-12 3 views
1

У меня есть функция таблицы, созданной в MSSQL, которая принимает в 2 paramateres 1. Дата окончания 2. Количество недель, чтобы вернуться , чтобы создать таблицу дат с даты начала недели ,Неожиданные результаты с SELECT INTO

В таблице ПЕРИОДА просто таблица с 1 колонкой (называется pPeriod) со всеми датами между «19971229» и «202»

CREATE FUNCTION [dbo].[Get_Week_Rank] 
( 
    -- Add the parameters for the function here 
    @PERIOD_END DATETIME, 
    @NUM_WEEKS INT 
) 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT A.PPERIOD TY_PPERIOD, B.PPERIOD TY_PWKSTART, DATEADD(YY, -1, A.PPERIOD) LY_PPERIOD, DATEADD(YY, -1, B.PPERIOD) LY_PWKSTART, B.CRNK WEEK_RANK FROM (
     SELECT PPERIOD, ROW_NUMBER() OVER (ORDER BY PPERIOD) CRNK FROM PERIODS 
      WHERE PPERIOD BETWEEN DATEADD(WW, @NUM_WEEKS - 1, @PERIOD_END) + 1 AND @PERIOD_END 
     ) AS A 
     JOIN (
      SELECT PPERIOD, ROW_NUMBER() OVER (ORDER BY CRNK % 7) CRNK FROM (
       SELECT PPERIOD, ROW_NUMBER() OVER (ORDER BY PPERIOD) CRNK FROM PERIODS 
        WHERE PPERIOD BETWEEN DATEADD(WW, @NUM_WEEKS, @PERIOD_END) + 1 AND @PERIOD_END 
       ) AS A 
       WHERE CRNK % 7 = 1 
      ) AS B ON (A.CRNK - 1)/7 = B.CRNK 
) 

Я заметил тогда, когда @NUM_WEEKS между -1 и -130 , результаты правильны при выполнении этого запроса:

SELECT * INTO #WEEKS FROM GET_WEEK_RANK('20160401', -104) 
SELECT * FROM #WEEKS ORDER BY 1 

Однако любое число ниже -130 (например, -156, -208), возвращаемые результаты все неправильно.

Wrong results

Вы можете видеть, что TY_PWKSTART все перемешалось и не синхронизированы с TY_PPERIOD. Если я выполнить запрос непосредственно, результаты возврата штрафа:

SELECT * FROM GET_WEEK_RANK('20160401', -140) 

Что может быть проблема? Я использую Microsoft SQL Server 2014

EDIT: Публикация изображений результатов Как вы можете видеть, оба запроса по существу, делают то же самое, но возвращаемые результаты различны. Порядок pWkStart в первом запросе при использовании SELECT INTO неверен.

Неправильные результаты:

SELECT * INTO #WEEK_WRONG FROM GET_WEEK_RANK('20160410', -140) 
SELECT * FROM #WEEK_WRONG ORDER BY 1 

WRONG RESULTS

Правильные результаты:

CREATE TABLE #WEEK_CORRECT (TY_PPERIOD DATETIME, TY_PWKSTART DATETIME, LY_PPERIOD DATETIME, LY_PWKTART DATETIME, WEEK_RANK INT) 
INSERT INTO #WEEK_CORRECT 
SELECT * FROM GET_WEEK_RANK('20160410', -140) 
SELECT * FROM #WEEK_CORRECT ORDER BY 1 

CORRECT RESULTS

EDIT2: Оказывается, что мой первоначальный запрос вызывал неожиданные результаты. Я исправил свой запрос и смог получить согласованные результаты от SELECT INTO и INSERT INTO. Просто разделяя код здесь:

CREATE FUNCTION [dbo].[Get_Week_Rank] 
( 
    @PERIOD_END DATETIME, 
    @NUM_WEEKS INT 
) 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT A.PPERIOD TY_PPERIOD, B.PPERIOD TY_PWKSTART, DATEADD(YY, -1, A.PPERIOD) LY_PPERIOD, DATEADD(YY, -1, B.PPERIOD) LY_PWKSTART, B.CRNK + 1 WEEK_RANK FROM (
      SELECT PPERIOD, (ROW_NUMBER() OVER (ORDER BY PPERIOD)-1)/7 CRNK FROM PERIODS 
       WHERE PPERIOD BETWEEN DATEADD(WW, @NUM_WEEKS, @PERIOD_END) + 1 AND @PERIOD_END 
     ) AS A 
     JOIN (
      SELECT PPERIOD, ROW_NUMBER() OVER (ORDER BY PPERIOD)-1 CRNK FROM (
       SELECT PPERIOD , ROW_NUMBER() OVER (PARTITION BY CRNK ORDER BY CRNK) CRNK FROM (
        SELECT PPERIOD, (ROW_NUMBER() OVER (ORDER BY PPERIOD)-1)/7 CRNK FROM PERIODS 
         WHERE PPERIOD BETWEEN DATEADD(WW, @NUM_WEEKS, @PERIOD_END) + 1 AND @PERIOD_END 
        ) AS A 
       ) AS A 
       WHERE CRNK = 1 
      ) AS B ON A.CRNK = B.CRNK 
) 
+0

Я понял его проблему SELECT INTO. Если я создаю временную таблицу и использую INSERT INTO, результаты будут точными. – jmstoh

+0

TVF, views или Select query не возвращают неправильные значения. Они * одинаковы под капотом. Поэтому версия сервера не имеет значения. Вы можете отлаживать свой код так же, как и любой другой оператор SELECT, - изолировать различные части, гарантировать, что вы получите значения, которые вы ожидаете для разных входов, выберете индивидуальные выборки и/или соединения, и проверите их и т. Д. –

+0

Кроме того, проблем нет с SELECT INTO. Если выбор из TVF возвращает ожидаемые данные, вы сможете создать новую таблицу с этими данными, используя SELECT INTO. –

ответ

1

Эта часть вашего запроса нарушается:

SELECT PPERIOD, ROW_NUMBER() OVER (ORDER BY CRNK % 7) CRNK FROM (
    ... 
) AS A 
WHERE CRNK % 7 = 1 

Поскольку где положение устанавливает, что CRNK % 7 равно 1, выражение ROW_NUMBER() волен назначить номера строк в любом порядке .Я думаю, что вы все равно хотите назначить номера строк в порядке, в которой работают PPERIOD или CRNK значения, и поэтому выражение должно вместо этого:

SELECT PPERIOD, ROW_NUMBER() OVER (ORDER BY CRNK) CRNK FROM (
    ... 
) AS A 
WHERE CRNK % 7 = 1 

Поскольку вы не предоставили достаточно выражения в ORDER BY для номеров строк, которые должны быть назначены однозначно, нет никакой гарантии на значения, присвоенные каждой строке.

+0

Спасибо! Да, с моим запросом возникла проблема. Я изменил его и добился последовательных результатов. Смешно, что использование INSERT INTO и SELECT INTO порождает разные результаты, но, как вы уже упоминали, это было только «правильно» по совпадению. – jmstoh

+0

@jmstoh - есть так много незначительных изменений, которые вы могли бы внести в запрос, который заставит оптимизатор запросов выбрать другой план выполнения. Или изменения на сервере или базе данных (разные тома данных, разные недавние истории транзакций, исправления и т. Д.), Которые внезапно заставят существующий запрос использовать другой план. –