Мне нравится использовать обертку (шаблон адаптера), когда я обертываю сам объект. Я не уверен, что использую это для переноса метода расширения, который не является частью объекта.
Я использую внутреннее 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/
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
)
Проблема с вашим запросом состоит в том, что при использовании предложения 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, важно использовать только функцию, которая возвращает значение столбец, если есть только одна подходящая строка.
Если ваша СУБД не поддерживает разные с несколькими столбцами, как это:
select distinct(col1, col2) from table
В общем случае множественный выбор можно безопасно выполнить следующим образом:
select distinct * from (select col1, col2 from table ) as x
Как это может работать на большинстве СУБД, и ожидается, что это будет быстрее, чем группировка по решению, поскольку вы избегаете функциональности группировки.
Я хочу выбрать отдельные значения из одного столбца «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)
Если вы соберете ответы, очистите и улучшите их, вы получите следующий превосходный запрос:
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 как равные. Следующие две строки для (saleprice, saledate)
будут квалифицироваться как «отличные» (хотя они выглядят идентично человеческому глазу):
(123, NULL)
(123, NULL)
Также передает уникальный индекс и почти в любом другом месте, поскольку значения NULL не сравниваются равен по стандарту SQL. См.
OTOH, GROUP BY
, DISTINCT
или DISTINCT ON ()
обрабатывают значения NULL как равные , Используйте соответствующий стиль запроса в зависимости от того, чего вы хотите достичь. Вы все еще можете использовать этот более быстрый запрос с IS NOT DISTINCT FROM
вместо =
для любого или всех сравнений, чтобы сделать сравнение NULL равным. Подробнее:
Если все сравниваемые столбцы определены NOT NULL
, в нем нет места разногласие. [тысяча сто пятьдесят семь]