Как мне (или я могу) ВЫБРАТЬ DISTINCT по нескольким столбцам?

Мне нравится использовать обертку (шаблон адаптера), когда я обертываю сам объект. Я не уверен, что использую это для переноса метода расширения, который не является частью объекта.

Я использую внутреннее Lazy Injectable Property любого типа Action, Func, Predicate или делегата и (g3)

    internal Func DoWorkMethod
    {
        [ExcludeFromCodeCoverage]
        get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); }
        set { _DoWorkMethod = value; }
    } private Func _DoWorkMethod;

Затем вы вызываете Func вместо фактического метода.

    public object SomeFunction()
    {
        var val = "doesn't matter for this example";
        return DoWorkMethod.Invoke(MyObjectProperty, val);
    }

Для более полного примера , проверьте http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/

368
задан Erwin Brandstetter 22 August 2014 в 00:07
поделиться

5 ответов

SELECT DISTINCT a,b,c FROM t

примерно примерно эквивалентно:

SELECT a,b,c FROM t GROUP BY a,b,c

Хорошая идея - привыкнуть к синтаксису GROUP BY, так как он более мощный.

По вашему запросу я бы сделал это так:

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )
407
ответ дан Joel Coehoorn 22 August 2014 в 00:07
поделиться

Проблема с вашим запросом состоит в том, что при использовании предложения GROUP BY (которое вы по сути делаете с помощью различных) вы можете использовать только столбцы, которые вы группируете или объединяете функции. Вы не можете использовать идентификатор столбца, потому что есть потенциально разные значения. В вашем случае всегда есть только одно значение из-за предложения HAVING, но большинство СУБД недостаточно умны, чтобы это распознать.

Однако это должно работать (и не требует объединения):

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

Вы также можете использовать MAX или AVG вместо MIN, важно использовать только функцию, которая возвращает значение столбец, если есть только одна подходящая строка.

23
ответ дан Christian Berg 22 August 2014 в 00:07
поделиться

Если ваша СУБД не поддерживает разные с несколькими столбцами, как это:

select distinct(col1, col2) from table

В общем случае множественный выбор можно безопасно выполнить следующим образом:

select distinct * from (select col1, col2 from table ) as x

Как это может работать на большинстве СУБД, и ожидается, что это будет быстрее, чем группировка по решению, поскольку вы избегаете функциональности группировки.

0
ответ дан Abdulhafeth Sartawi 22 August 2014 в 00:07
поделиться

Я хочу выбрать отдельные значения из одного столбца «GrondOfLucht», но они должны быть отсортированы в порядке, указанном в столбце «сортировка». Я не могу получить отличительные значения только одного столбца, используя

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

. Он также даст сортировку столбца, и, поскольку «GrondOfLucht» И «сортировка» не уникальны, результатом будут ВСЕ строки.

используйте GROUP, чтобы выбрать записи 'GrondOfLucht' в порядке, указанном в 'sorting

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
1
ответ дан frans eilering 22 August 2014 в 00:07
поделиться

Если вы соберете ответы, очистите и улучшите их, вы получите следующий превосходный запрос:

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

, который на намного быстрее, чем любой из них. Уменьшает производительность принятого в настоящее время ответа в 10-15 раз (в моих тестах на PostgreSQL 8.4 и 9.1).

1146 Но это все еще далеко от оптимального. Используйте NOT EXISTS (анти-) полусоединение для еще лучшей производительности. EXISTS является стандартным SQL, существует вечно (по крайней мере, с PostgreSQL 7.2, задолго до того, как был задан этот вопрос) и идеально соответствует представленным требованиям:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT FROM sales s1                     -- SELECT list can be empty for EXISTS
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   )
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

db <> fiddle здесь
Старая скрипта SQL

Уникальный ключ для идентификации строки

Если у вас нет основного или уникального Ключ для таблицы (id в примере), вы можете заменить системный столбец ctid для целей этого запроса (но не для некоторых других целей):

   AND    s1.ctid <> s.ctid

Каждая таблица должна иметь первичный ключ. Добавьте еще один, если у вас его еще не было. Я предлагаю столбец serial или IDENTITY в Postgres 10+.

Связанные:

Как это быстрее?

Подзапрос в EXISTS anti-semi-join может перестать оценивать, как только будет найден первый дуплекс (нет смысла смотреть дальше). Для базовой таблицы с небольшим количеством дубликатов это лишь немного более эффективно. С большим количеством дубликатов это становится способом более эффективным.

Исключить пустые обновления

Для строк, в которых уже есть status = 'ACTIVE', это обновление ничего не изменит, но все равно вставит новую версию строки за полную стоимость (применяются незначительные исключения). Обычно вы этого не хотите. Добавьте еще одно условие WHERE, как показано выше, чтобы избежать этого и сделать его еще быстрее:

Если определено status NOT NULL, вы можете упростить до:

AND status <> 'ACTIVE';

Тонкая разница в обработке NULL

Этот запрос (в отличие от принятого в настоящее время ответа Джоэля ) не рассматривает значения NULL как равные. Следующие две строки для (saleprice, saledate) будут квалифицироваться как «отличные» (хотя они выглядят идентично человеческому глазу):

(123, NULL)
(123, NULL)

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

OTOH, GROUP BY, DISTINCT или DISTINCT ON () обрабатывают значения NULL как равные , Используйте соответствующий стиль запроса в зависимости от того, чего вы хотите достичь. Вы все еще можете использовать этот более быстрый запрос с IS NOT DISTINCT FROM вместо = для любого или всех сравнений, чтобы сделать сравнение NULL равным. Подробнее:

Если все сравниваемые столбцы определены NOT NULL, в нем нет места разногласие. [тысяча сто пятьдесят семь]

321
ответ дан Erwin Brandstetter 22 August 2014 в 00:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: