Оператор IN в SQL Оператор не работает? - PullRequest
0 голосов
/ 20 февраля 2020

На SQL сервере, у меня есть таблица MyTable со следующими 3 столбцами: P (bigint), F (bigint), D (bigint).

Теперь мне нужно сделать следующее: сгруппируйте все записи по одному значению P, затем в каждой группе вычислите следующее значение:

V = ABS((P & 0xFFFFFFFF) * 256 - F)

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

Поэтому я пишу оператор SQL следующим образом:

DELETE FROM MyTable WHERE (P, ABS((P & 0xFFFFFFFF) * 256 - F)) NOT IN (SELECT P, MIN(ABS((P & 0xFFFFFFFF) * 256 - F)) FROM MyTable GROUP BY P HAVING COUNT(*) > 1)

Но на SQL Server я получу следующую ошибку:

Msg 4145 SQL Server An expression of non-boolean type specified in a context where a condition is expected,near ','

Почему ? Также работает ли поразрядно и & в SQL Server 2005? У меня есть только SQL Server 2008 R2 и в онлайн-документе https://docs.microsoft.com/en-us/sql/t-sql/language-elements/bitwise-and-transact-sql?view=sql-server-ver15 не указано, поддерживает ли он 2005 и 2008 годы.

Update1

P, F, D - все типы bigint.

Update2

С помощью других, я наконец пишу запрос с NOT EXISTS, как показано ниже:

Метод 1: УДАЛИТЬ t ИЗ MyTable t, ГДЕ НЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ (ВЫБРАТЬ P, МИН (ABS ((P & 0xFFFFFFFF) * 256 - F)) как minpf ИЗ ГРУППЫ MyTable ПО P) tt ГДЕ tt .P = tP AND tt.minpf = ABS ((tP & 0xFFFFFFFF) * 256 - tF))

Примечание. Я удаляю HAVE COUNT (*)> 1, в противном случае оператор также будет удалите те записи, которые находятся в группе только с одной записью.

Хотя это работает, я сомневаюсь в его эффективности. Поскольку в большинстве групп (сгруппировать по P) будет только одна запись, при расчете minpf в такой группе и последующем удалении записи с вычисленным значением <> minpf теряется время (в таком случае записи не удаляются). группа). Так что просто интересно, есть ли лучший способ сделать то же самое?

Обновление 3

Я тестирую производительность моего метода (метод 1) с двумя методами Гордон предоставляется (с незначительной ревизией)

Метод 2:

УДАЛИТЬ t ИЗ MyTable t СЛЕДУЮЩЕЕ СОЕДИНЕНИЕ (ВЫБЕРИТЕ P, MIN (ABS ((P & 0xFFFFFFFF) * 256 - F)) как minpf ОТ MyTable GROUP BY P) tt ON tt.p = tp AND tt.minpf = (tt.P & 0xFFFFFFFF) * 256 - tt.F) ГДЕ tt.P НЕДЕЙСТВИТЕЛЬНО;

Метод 3:

УДАЛИТЬ t ОТ (ВЫБРАТЬ t. *, ROW_NUMBER () НАД (РАЗДЕЛЕНИЕ ПО ПОРЯДКУ В АБС ((P & 0xFFFFFFFF) * 256 - F)) как последовательность ОТ MyTable t) t ГДЕ seqnum> 1;

Ниже приведены данные о производительности:

Первый тест:

(затронуто 22721 строк) Метод 1: 16094

(затронут 22721 строк) Метод 2: 17156

(затронуто 22721 строк) Метод 3: 12188

Второй тест:

(затронуто 22721 строк) Метод 1: 26297

(затронуто 22721 строк) Метод 2 : 27562

(затронуто 22721 рядов ) Метод 3: 11625

3-й тест:

(затронуто 22721 строк) Метод 1: 26297

(затронуто 22721 строк) Метод 2: 27359

(Затронуто 22721 строка) Метод 3: 11578

Таким образом, исходя из теста, метод 3 имеет наилучшую производительность.

Ответы [ 4 ]

1 голос
/ 20 февраля 2020

На SQL сервере просто используйте JOIN:

DELETE t
    FROM MyTable t LEFT JOIN
         (SELECT P, MIN(ABS((P & 0xFFFFFFFF) * 256 - F)) as minpf
          FROM MyTable
          GROUP BY P
          HAVING COUNT(*) > 1
         ) tt
         ON tt.p = t.p AND tt.minpf = (tt.P & 0xFFFFFFFF) * 256 - tt.F)
    WHERE tt.P IS NULL;

Или, проще, используйте оконные функции:

DELETE t
    FROM (SELECT t.*,
                 ROW_NUMBER(*) OVER (PARTITION BY P ORDER BY ABS((P & 0xFFFFFFFF) * 256 - F) as seqnum
          FROM MyTable t
         ) t
     WHERE seqnum > 1;
0 голосов
/ 20 февраля 2020

запрос select после IN должен возвращать только один столбец, сначала проверьте его

0 голосов
/ 20 февраля 2020

Попробуйте это:

DELETE FROM MyTable 
WHERE concat(P, ABS((P & 0xFFFFFFFF) * 256 - F)) NOT IN (SELECT concat( P, MIN(ABS((P & 
0xFFFFFFFF) * 256 - F))) FROM MyTable GROUP BY P HAVING COUNT(*) > 1)
0 голосов
/ 20 февраля 2020

IN операторы работают, но они не работают так, как вы их используете - просто так. Содержимое IN - это список значений сравнения, а не другой оператор sql.

В вашем случае вы не делаете IN - вы удаляете форму select с помощью join и используете ее для определения удаляемых строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...