Проблема с вычисляемым столбцом в SQL

У меня есть таблица, из которой я хочу выбрать подмножество столбцов, но также добавить в конце вычисляемый столбец в зависимости от того, где вы находитесь в очереди. Имеются следующие поля (имеющие значение):

id: int, автоинкремент, время ответа первичного ключа: datetime, nullable

По умолчанию, когда что-то отправляется в очередь, его время ответа равно NULL. Итак, я хочу выбрать идентификатор вещи в очереди, а также ее ранг в очереди (т.е. ранг 1 — это следующий элемент, на который нет ответа, и т. д.). Вот о чем я думал:

ранг - идентификатор - COUNT (идентификаторы ниже моего идентификатора, где время ответа не равно нулю). Однако у меня проблема с синтаксисом этого запроса:

SELECT id AS outerid, COUNT(
    SELECT * FROM tablename WHERE id<outerid AND answertime IS NOT NULL
)
FROM tablename 
WHERE answertime IS NULL;

Теперь, очевидно, это неправильно, потому что я вполне уверен, что вы не можете встроить выбор внутри агрегатной функции, точно так же переключение SELECT и COUNT не работает, поскольку вы не можете встроить SELECT в этот момент в коде (его можно использовать только в предложении WHERE).

Возможно ли это сделать только с помощью SQL или мне нужно добавить некоторую логику в конце программы?

Если это поможет, я делаю это на SQL Server 2008, хотя сомневаюсь, что это принесет какую-либо пользу.


person wibarr    schedule 20.01.2012    source источник
comment
НЕТ времени, чтобы привести хороший пример, но поищите функцию ROW_NUMBER. Если я вас правильно понял, я думаю, это будет то, что вы хотите.   -  person HLGEM    schedule 20.01.2012


Ответы (3)


Вы можете сделать это, вы просто не можете использовать SELECT * в агрегированном подзапросе. Попробуйте это, которое получает значение COUNT как скалярный результат:

SELECT
   id AS outerid,
   (SELECT COUNT(Id) FROM tablename
    WHERE id<outie.id AND answertime IS NOT NULL)
FROM tablename outie
WHERE answertime IS NULL;

Возможно, вам придется выбирать между использованием COUNT(*), COUNT(Id) или какого-либо другого столбца в зависимости от того, что вам действительно нужно.

person Yuck    schedule 20.01.2012
comment
А, я вижу, чего мне не хватало, когда я пробовал внутренний запрос SELECT; Я пропустил бит outie FROM tablename, чтобы он мог различать идентификаторы. Спасибо! - person wibarr; 21.01.2012

SELECT id AS outerid,
(SELECT COUNT(*) FROM tablename WHERE id < outerid AND answertime IS NOT NULL) AS othercol
FROM tablename -- ?
WHERE answertime IS NULL;

Кроме того, где оператор FROM?

person WoLfulus    schedule 20.01.2012
comment
Я добавил к вопросу оператор FROM; Я упростил это из моего фактического запроса и забыл указать это. - person wibarr; 21.01.2012

Как предложил @HLGEM, вы можете использовать ROW_NUMBER() для получения результатов. Этот метод включает ранжирование строк в tablename по id без разделения на и по id с разделением на answertime. Разница между ранжированием для каждой строки, где answertime равно NULL, даст вам то же значение, что и то, которое вы вычисляете, используя COUNT() в подзапросе.

Вот реализация метода:

;
WITH ranked AS (
  SELECT
    *,
    Rnk     = ROW_NUMBER() OVER (                        ORDER BY id),
    PartRnk = ROW_NUMBER() OVER (PARTITION BY answertime ORDER BY id)
  FROM tablename
)
SELECT
  id,  /* AS outerid, if you like */
  Cnt = Rnk - PartRnk
FROM ranked
WHERE answertime IS NULL
person Andriy M    schedule 20.01.2012