2014-12-18 3 views
1

Возникли запрос вроде следующего (сокращенный и переименованный для простоты)Выберите в Select, используя параметры

SELECT 
    SOME_COLUMN AS value1, 
    SOME_COMMON_ID as commonID, 
    SOME_TAG as tagID, 
    SOME_TIMESTAMP as endTime, 
    (SELECT 
     SOME_TIMESTAMP AS beginTime 
    FROM 
     EVENTLIST 
    WHERE 
     EVENTLIST.SOME_TAG = 'BEGIN' 
     AND EVENTLIST.SOME_COMMON_ID = commonID /* <-- Invalid column name commonID */ 
), 
    endTime - beginTime AS duration 
FROM 
    EVENTLIST 
JOIN 
    (...some irrelevant lookups on other tables) 
WHERE 
    (...some criteria...) 

То, что я хотел бы достичь:

Эта таблица регистрирует некоторые события, время, на котором событие происходит в SOME_TIMESTAMP. Несколько событий сгруппированы с помощью общего идентификатора, называемого SOME_COMMON_ID. Тип события хранится в SOME_TAG

Для каждого из событий я хотел бы выбрать длительность текущего события, так как событие, имеющее тег BEGIN

Как добиться этого в SQL Server?

+0

Это нормально вычислить разницу в другом месте. Однако, как я могу выбрать внутренний запрос? Я изменил вопрос, чтобы более точно описать проблему. – Atmocreations

ответ

0

Это было даже проще, чем я думал.

SELECT 
    SOME_COLUMN AS value1, 
    SOME_COMMON_ID as commonID, 
    SOME_TAG as tagID, 
    SOME_TIMESTAMP as endTime, 
    (SELECT 
     DATEDIFF(SECOND, e2.SOME_TIMESTAMP, e1.SOME_TIMESTAMP) AS duration 
     /* ^-- calc the diff here, not in the outer query */ 
    FROM 
     EVENTLIST e2 
    WHERE 
     e2.SOME_TAG = 'BEGIN' 
     AND e2.SOME_COMMON_ID = e1.SOME_COMMON_ID /* <-- qualify table names */ 
) 
FROM 
    EVENTLIST e1 /* <-- name required */ 
JOIN 
    (...some irrelevant lookups on other tables) 
WHERE 
    (...some criteria...) 

Мне пришлось квалифицировать таблицы и рассчитать разницу прямо во внутреннем запросе. И я должен рассчитать разницу во внутреннем запросе, так что это возможно.

+0

Это может быть довольно медленным из-за подзапроса. –

+0

Спасибо за ввод. Это неудача =) Я не собираюсь выполнять это на миллиардах записей. – Atmocreations

+0

Если вы не слишком далеко, попробуйте его с помощью метода join. Предполагая, что 'SOME_COMMON_ID' имеет индекс, вы должны получить отличную производительность. –

0

Если вы измените подзаголовок, чтобы получить BEGIN время в JOIN, вам будет легче обойти проблему с именами столбцов, а также, вероятно, получить некоторую производительность.

Используя текущий шаблон, расчет временной метки должен происходить на более высоком уровне вложенности запросов, поскольку псевдонимы, назначенные для значения подзапроса и обычного значения таблицы, недоступны для использования внутри SELECT на том же уровне запросов. Это также решается с помощью JOIN.

SELECT 
    curevt.SOME_COLUMN AS value1, 
    curevt.SOME_COMMON_ID as commonID, 
    curevt.SOME_TAG as tagID, 
    curevt.SOME_TIMESTAMP as endTime, 
    beginevt.SOME_TIMESTAMP AS beginTime, 
    -- In the JOIN scenario, the calc can happen here, without using the alias 
    curevt.SOME_TIMESTAMP - beginevt.SOME_TIMESTAMP AS duration 
FROM 
    -- The table first for current events 
    EVENTLIST curevt 
    -- Join against itself for the BEGIN events 
    INNER JOIN EVENTLIST beginevt 
    -- Join condition on SOME_COMMON_ID and also the BEGIN event 
    ON curevt.SOME_COMMON_ID = beginevt.SOME_COMMON_ID 
    AND beginevt.SOME_TAG = 'BEGIN' 

Вот пример, используя DATEDIFF() найти разницу минут с datetime колоннами. http://sqlfiddle.com/#!6/b02ac/7, хотя похоже, что у вас может быть что-то другое, как временные метки Unix. Сделайте свой расчет соответствующим образом, концепция будет одинаковой в любом случае.

Примечание: если вы будете иметь некоторые значения SOME_COMMON_ID без соответствующего BEGIN случае, вам нужно будет использовать LEFT JOIN здесь вместо INNER JOIN, чтобы гарантировать, что они показывают в наборе результатов. Вам также может потребоваться обработать расчет duration немного по-другому с IFNULL() или аналогичным, потому что это будет NULL.

1

Позволяет создавать тестовые данные

DECLARE @EventList TABLE 
(
    SOME_COLUMN_ID int, 
    SOME_COLUMN varchar(20), 
    SOME_TAG varchar(20), 
    SOME_TIMESTAMP datetime 
) 

INSERT INTO @EventList 
(SOME_COLUMN_ID, SOME_COLUMN, SOME_TAG, SOME_TIMESTAMP) 
VALUES 
(1, 'Exporting', 'BEGIN', DATEADD(HOUR, -5, GETDATE())), 
(1, 'Exporting', 'GOING', DATEADD(HOUR, -4, GETDATE())), 
(1, 'Exporting', 'STILL_GOING', DATEADD(HOUR, -3, GETDATE())), 
(1, 'Exporting', 'GONE', DATEADD(HOUR, -2, GETDATE())), 
(1, 'Exporting', 'END', DATEADD(HOUR, -1, GETDATE())), 
(2, 'Parsing1', 'BEGIN', DATEADD(HOUR, -5, GETDATE())), 
(2, 'Parsing2', 'GOING', DATEADD(HOUR, -4, GETDATE())), 
(2, 'Parsing3', 'STILL_GOING', DATEADD(HOUR, -3, GETDATE())), 
(2, 'Parsing4', 'GONE', DATEADD(HOUR, -2, GETDATE())); 

Теперь я собираюсь сделать КТР заказать события по времени и распределяли по ID

WITH T AS 
(
    SELECT *, 
    ROW_NUMBER() OVER (PARTITION BY SOME_COLUMN_ID ORDER BY SOME_TIMESTAMP) RN 
    FROM @EventList 
) 

Теперь мы будем тянуть все события находят одно после и получают продолжительность каждого шага, я также проверяю, удался ли процесс в END, иначе я использую время, чтобы найти продолжительность.

SELECT 
    T1.SOME_COLUMN_ID, 
    T1.SOME_COLUMN, 
    T1.SOME_TAG, 
    T1.SOME_TIMESTAMP AS BeginTime, 
    (CASE WHEN t1.SOME_TAG != 'END' THEN ISNULL(t2.SOME_TIMESTAMP, GETDATE()) ELSE NULL END) EndTime, 
    (CASE WHEN t1.SOME_TAG != 'END' THEN DATEDIFF(MINUTE, t1.SOME_TIMESTAMP, ISNULL(t2.SOME_TIMESTAMP, GETDATE())) ELSE NULL END) Duration 
FROM T t1 
LEFT JOIN T t2 
    ON t1.SOME_COLUMN_ID = t2.SOME_COLUMN_ID 
    AND t1.RN = t2.RN - 1 

Вот результат:

SOME_COLUMN_ID SOME_COLUMN SOME_TAG  BeginTime     EndTime    Duration 
1    Exporting BEGIN  2014-12-18 05:31:06.090 2014-12-18 06:31:06.090 60 
1    Exporting GOING  2014-12-18 06:31:06.090 2014-12-18 07:31:06.090 60 
1    Exporting STILL_GOING 2014-12-18 07:31:06.090 2014-12-18 08:31:06.090 60 
1    Exporting GONE   2014-12-18 08:31:06.090 2014-12-18 09:31:06.090 60 
1    Exporting END   2014-12-18 09:31:06.090 NULL NULL 
2    Parsing1 BEGIN  2014-12-18 05:31:06.090 2014-12-18 06:31:06.090 60 
2    Parsing2 GOING  2014-12-18 06:31:06.090 2014-12-18 07:31:06.090 60 
2    Parsing3 STILL_GOING 2014-12-18 07:31:06.090 2014-12-18 08:31:06.090 60 
2    Parsing4 GONE   2014-12-18 08:31:06.090 2014-12-18 10:31:06.090 120