Nano Hash - криптовалюты, майнинг, программирование

Использование HAVING без GROUP BY не работает должным образом

Я начинаю изучать SQL Server, в документации, найденной в msdn утверждает следующее

HAVING обычно используется с предложением GROUP BY. Когда GROUP BY не используется, существует неявная единая агрегированная группа.

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

у меня такая таблица

CREATE TABLE [dbo].[_abc]
(
    [wage] [int] NULL
) ON [PRIMARY]
GO

INSERT INTO [dbo].[_abc] (wage)
VALUES (4), (8), (15), (30), (50) 
GO

Теперь, когда я запускаю этот запрос, я получаю сообщение об ошибке

select * 
from [dbo].[_abc]
having sum(wage) > 5

Ошибка:

введите здесь описание изображения


  • Попробуйте: select sum(wage), count(1) from [dbo].[_abc] having sum(wage)>5 10.11.2018
  • Что именно вы хотите, чтобы этот запрос возвращал? Можете ли вы добавить пример ожидаемого результата? 10.11.2018
  • @johey, я просто хочу узнать, как реализовать без предложения groupBy, я использовал эту таблицу, потому что она проста и ее легко понять 10.11.2018
  • Как уже было сказано Джоном и Пратапом, при использовании группы по и/или наличия вы не можете просто использовать все, что хотите, в списке выбора. Согласно msdn (выписка, которую вы скопировали), без группы результат будет помещен в неявную единую агрегированную группу. Таким образом, использование * в вашем выборе (или явное использование столбца заработной платы) не будет работать, поскольку эти разные значения нельзя преобразовать только в одну группу (одну результирующую запись). 10.11.2018
  • Документация верна, просто вам также нужно прочитать документацию о группе. 10.11.2018
  • Я думаю, что иметь без группы by очень странно и редко используется. Но если вы настаиваете на его использовании, попробуйте следующее: select sum(wage) from [dbo].[_abc] having sum(wage)>5 (что соответствует первому комментарию Джона здесь, только без столбца count) 10.11.2018
  • @johey, можете ли вы объяснить мне, почему я получаю результат с выбранной суммой (зарплатой) от [dbo]. [_abc] с суммой (зарплатой) > 5, но не с выбранной заработной платой с [dbo]. [_abc] с суммой ( зарплата)›5 спасибо 10.11.2018
  • Да, с select wage вы просите выбрать всю заработную плату (поэтому необходимо вернуть несколько записей), с select sum(wage) вы получите только один результат (сумма всех заработков). Неявная одиночная совокупная группа не позволяет возвращать несколько результатов, поэтому вы получаете ошибку. 10.11.2018

Ответы:


1

Документация верна; то есть вы можете запустить этот оператор:

select sum(wage) sum_of_all_wages
, count(1) count_of_all_records
from [dbo].[_abc] 
having sum(wage) > 5

Причина, по которой ваш оператор не работает, связана с select *, что означает выбор значения каждого столбца. Когда group by нет, все записи агрегируются; то есть вы получаете только 1 запись в своем наборе результатов, которая должна представлять каждую запись. Таким образом, вы можете* включать только значения, полученные путем применения агрегатных функций к вашим столбцам; а не сами колонки. * конечно, вы также можете указать константы, поэтому select 'x' constant, count(1) cnt from myTable будет работать.

Есть не так много вариантов использования, которые я могу придумать, где вы хотели бы использовать наличие без группы, но, безусловно, это можно сделать, как показано выше.

NB: если вам нужны все строки, в которых заработная плата больше 5, вместо этого вы должны использовать предложение where:

select * 
from [dbo].[_abc] 
where wage > 5

Точно так же, если вы хотите, чтобы сумма всех заработных плат была больше 5, вы можете сделать это

select sum(wage) sum_of_wage_over_5 
from [dbo].[_abc] 
where wage > 5

Или, если вы хотите сравнить сумму заработной платы более 5 с заработной платой ниже:

select case when wage > 5 then 1 else 0 end wage_over_five
, sum(wage) sum_of_wage
from [dbo].[_abc] 
group by case when wage > 5 then 1 else 0 end 

См. выполняемые примеры здесь.


Обновление на основе комментариев:

Вам нужно having для использования агрегатных функций?

Нет. Вы можете запустить select sum(wage) from [dbo].[_abc]. Когда агрегатная функция используется без предложения group by, это как если бы вы группировали по константе; то есть select sum(wage) from [dbo].[_abc] group by 1.

Документация просто означает, что хотя обычно у вас будет оператор having с оператором group by, можно исключить group by / в таких случаях оператор having, как и оператор select, будет обрабатывать ваш запрос так, как если бы вы указали group by 1.

В чем смысл?

Трудно придумать много хороших вариантов использования, поскольку вы возвращаете только одну строку, а оператор having является фильтром для этого.

Одним из вариантов использования может быть то, что вы пишете код для мониторинга ваших лицензий на какое-то программное обеспечение; если у вас меньше пользователей, чем лицензий на пользователя, все хорошо / вы не хотите видеть результат, так как вам все равно. Если у вас есть больше пользователей, вы хотите знать об этом. Например.

declare @totalUserLicenses int = 100
select count(1) NumberOfActiveUsers
, @totalUserLicenses NumberOfLicenses
, count(1) - @totalUserLicenses NumberOfAdditionalLicensesToPurchase
from [dbo].[Users]
where enabled = 1
having count(1) > @totalUserLicenses 

Разве выбор не имеет отношения к предложению наличия?

Да и нет. Наличие — это фильтр ваших агрегированных данных. Select указывает, какие столбцы/информацию нужно вернуть. Таким образом, вы должны спросить: «Как будет выглядеть результат?» т. е. Учитывая, что нам пришлось эффективно применять group by 1, чтобы использовать оператор having, как SQL должен интерпретировать select *? Поскольку в вашей таблице есть только один столбец, это будет означать select wage; но у нас есть 5 строк, поэтому 5 разных значений wage и только 1 строка в результате, чтобы показать это.

Я думаю, вы могли бы сказать: «Я хочу вернуть все строки, если их сумма больше 5; в противном случае я не хочу возвращать строки». Если бы это было вашим требованием, это могло бы быть достигнуто различными способами; одним из которых будет:

select *
from [dbo].[_abc] 
where exists 
(
    select 1 
    from [dbo].[_abc] 
    having sum(wage) > 5
) 

Однако мы должны написать код, соответствующий требованиям, а не ожидать, что код поймет наши намерения.

Другой способ представить having как оператор where, применяемый к подзапросу. т.е. ваше исходное утверждение эффективно гласит:

select wage
from
(
    select sum(wage) sum_of_wage
    from [dbo].[_abc]
    group by 1
) singleRowResult
where sum_of_wage > 5

Это не сработает, потому что wage недоступно для внешнего запроса; возвращается только sum_of_wage.

10.11.2018
  • причина, по которой я привел этот небольшой пример, заключается в том, что я хочу понять, как использовать его без предложения grooupBy. 10.11.2018
  • мой вопрос в том, как я могу использовать предложение наличия в таблице, которую я разработал 10.11.2018
  • У меня есть некоторый вопрос относительно ответа, который вы опубликовали. Причина, по которой ваше утверждение не работает, заключается в том, что select * 1. столбец в предложении select не имеет отношения к предложению наличия, потому что все предложение наличия предоставляет нам возможность использовать агрегатную функцию, верно? если нет объясните пожалуйста спасибо 10.11.2018
  • Надеюсь, мой обновленный ответ имеет больше смысла ... дайте мне знать. Как человек, изучающий язык, ваш подход отличается от подхода большинства людей; вы спрашиваете how can I use having without using group by как способ понять это. В стандартных случаях использования вы сначала должны иметь в виду цель, и ваш вопрос будет how do I achieve this. Как уже упоминалось, трудно придумать много примеров, где использование having без group by имело бы смысл; поэтому я бы посоветовал сделать мысленную пометку, что это вариант, и перейти к изучению чего-то еще; то в будущем, если вы столкнетесь с вариантом использования, надеюсь, вы вспомните это 10.11.2018

  • 2

    HAVING без пункта GROUP BY вполне допустимо, но вот что вам нужно понять:

    • The result will contain zero or one row
      • The implicit GROUP BY will return exactly one row even if the WHERE condition matched zero rows
      • HAVING сохранит или удалит эту единственную строку в зависимости от условия
    • Любой столбец в предложении SELECT должен быть обернут внутри агрегатной функции.
    • Вы также можете указать выражение, если оно функционально не зависит от столбцов.

    Это означает, что вы можете сделать это:

    SELECT SUM(wage)
    FROM employees
    HAVING SUM(wage) > 100
    -- One row containing the sum if the sum is greater than 5
    -- Zero rows otherwise
    

    Или даже это:

    SELECT 1
    FROM employees
    HAVING SUM(wage) > 100
    -- One row containing "1" if the sum is greater than 5
    -- Zero rows otherwise
    

    Эта конструкция часто используется, когда вам нужно проверить, было ли найдено совпадение для агрегата:

    SELECT *
    FROM departments
    WHERE EXISTS (
        SELECT 1
        FROM employees
        WHERE employees.department = departments.department
        HAVING SUM(wage) > 100
    )
    -- all departments whose employees earn more than 100 in total
    
    10.11.2018

    3

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

    Как показано ниже, пример

     USE AdventureWorks2012 ;  
    GO  
    SELECT SalesOrderID, SUM(LineTotal) AS SubTotal  
    FROM Sales.SalesOrderDetail  
    GROUP BY SalesOrderID  
    HAVING SUM(LineTotal) > 100000.00  
    ORDER BY SalesOrderID ;  
    

    В вашем случае у вас нет столбца идентификаторов для вашей таблицы, он должен выглядеть следующим образом:

    Alter _abc
    Add Id_new Int Identity(1, 1)
    Go
    
    10.11.2018
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..