Перекрестное применение для поиска всех дат

#sql #sql-server #sql-server-2008

#sql #sql-сервер #sql-server-2008

Вопрос:

У меня есть таблица, в которой будут храниться даты текущего года, у меня также есть дата начала в этой таблице. Есть ли какая-либо возможность получить все даты между текущей и начальной датой с помощью ПЕРЕКРЕСТНОГО ПРИМЕНЕНИЯ.

 Ex: 
Current_Year         Start_Date
2014-06-12           2011-01-01  
2014-04-12           2011-01-01 
2014-02-12           2011-01-01
2014-01-12           2011-01-01

I want result set like 

Year
2014-06-12           2011-01-01  
2014-04-12           2011-01-01 
2014-02-12           2011-01-01
2014-01-12           2011-01-01
2013-06-12           2011-01-01  
2013-04-12           2011-01-01 
2013-02-12           2011-01-01
2013-01-12           2011-01-01
2012-06-12           2011-01-01  
2012-04-12           2011-01-01 
2012-02-12           2011-01-01
2012-01-12           2011-01-01
2011-06-12           2011-01-01  
2011-04-12           2011-01-01 
2011-02-12           2011-01-01
2011-01-12           2011-01-01
  

Комментарии:

1. и как это cross apply выглядит?

2. Но почему так важно, чтобы вы использовали ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ? этот результат может быть достигнут и другими способами.

Ответ №1:

Следующее даст желаемые результаты с использованием ПЕРЕКРЕСТНОГО ПРИМЕНЕНИЯ:

 WITH T AS 
(   SELECT  Current_Year = CAST(cy AS DATE), Start_Date = CAST(sd AS DATE)
    FROM    (VALUES
                ('2014-06-12', '2011-01-01'),
                ('2014-04-12', '2011-01-01'),
                ('2014-02-12', '2011-01-01'),
                ('2014-01-12', '2011-01-01')
            ) t (cy, sd)
)
SELECT  Current_Year = DATEADD(YEAR, - n.Number, t.Current_Year),
        t.Start_Date
FROM    T
        CROSS APPLY 
        (   SELECT  TOP 1000 ROW_NUMBER() OVER (ORDER BY a.object_id) - 1
            FROM    sys.all_objects AS a
        ) AS n (Number)
WHERE   DATEADD(YEAR, - n.Number, t.Current_Year) > t.Start_Date;
  

Но ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ будет работать одинаково хорошо и, возможно, будет иметь больше смысла семантически, хотя план выполнения в конечном итоге останется тем же.

Комментарии:

1. это довольно легко сделать с помощью cte и #temp, но из-за требований моего проекта, который содержит объемные данные, не может этого сделать, я попробовал #temp и cte, но время выполнения слишком велико. Поэтому мне нужен какой-то механизм, который может сделать это с перекрестным применением.

Ответ №2:

 DECLARE @TAB1 TABLE (CURRENT_YEAR DATE)
INSERT INTO @TAB1 VALUES('2014-06-12'),('2014-04-12'),('2014-02-12'),('2014-01-12')

DECLARE @TAB2 TABLE (CURRENT_YEAR DATE)
INSERT INTO @TAB2 VALUES('2011-01-01'),('2011-01-01'),('2011-01-01'),('2011-01-01')
  

SQL:

 SELECT  DATEADD(YY,
        LU.[ROW] * (-1),A.CURRENT_YEAR) [YEAR],LU.CURRENT_YEAR [Static_YEAR]
FROM    @TAB1 A,
        (SELECT *,(ROW_NUMBER() OVER (ORDER BY CURRENT_YEAR)) - 1 [ROW] FROM @TAB2) LU
  

Результат

введите описание изображения здесь

Ответ №3:

Это должно сработать в вашем случае:

 SELECT *
FROM (SELECT Current_Year
      FROM TableName) AS Current_Year
, (SELECT Start_Date
   FROM TableName) AS Start_Date
  

Перекрестное применение используется, когда у вас есть функция, которая возвращает скалярное значение в правой части вашего соединения.