SQL Count уникальные объекты, определенные параметрами - PullRequest
5 голосов
/ 12 июня 2010

У меня есть таблица с:

id | parameter
 1 | A
 1 | B
 2 | A
 3 | A
 3 | B

, которые представляют объекты, определенные со значениями как:

 1 -> A,B
 2 -> A
 3 -> A,B

Я хочу подсчитать количество объектов с различными параметрами, используя SQLзапрос, поэтому в этом случае это будут 2 уникальных объекта, так как 1 и 3 имеют одинаковые параметры.

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

База данных - это Microsoft SQL Server 2000. Но я не против узнать решение для других баз данных.

Ответы [ 5 ]

3 голосов
/ 12 июня 2010

Если я правильно понимаю, вам нужно количество различных комбинаций из parameter с на id, представленных в вашей таблице, возможно, с количеством объектов, демонстрирующих каждую из этих различных комбинаций.

Я не могу говорить за SQL Server, но в MySQL вы могли бы сделать что-то вроде этого:

  SELECT parameter_set, COUNT(*) AS entity_count
    FROM (
          -- Here we "flatten" the different parameter combinations per id
             SELECT id,
                    GROUP_CONCAT(parameter ORDER BY parameter) AS parameter_set
               FROM tbl
           GROUP BY id
         ) d
GROUP BY parameter_set;

, который даст вам это:

 parameter_set | entity_count
---------------+--------------
 A,B           |            2   -- two entities have params A, B
 A             |            1   -- one entity has param A

и SELECT COUNT(DISTINCT parameter_set FROM (... flattening query ...)) d даст вам количество различных наборов параметров.

2 голосов
/ 12 июня 2010

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

Логика здесь заключается в том, чтобы сначала удалить дубликаты объектов, а затем подсчитать оставшиеся идентификаторы. Подзапрос NOT IN представляет объекты, которые имеют соответствующий объект с меньшим идентификатором. Подзапрос объединяет параметры двух объектов t1 и t2, а затем подсчитывает, сколько параметров соответствует каждой паре t1 / t2. Если количество совпадающих параметров совпадает с количеством параметров в t1 и в t2, то t2 и t1 являются совпадениями, и мы должны исключить t1 из набора результатов.

DECLARE @tab TABLE (ID int, parameter varchar(2));

INSERT INTO @tab
SELECT 1, 'A' UNION ALL
SELECT 1, 'B' UNION ALL
SELECT 2, 'A' UNION ALL
SELECT 3, 'A' UNION ALL
SELECT 3, 'B' UNION ALL
SELECT 4, 'A' UNION ALL
SELECT 5, 'C' UNION ALL
SELECT 5, 'D';

SELECT
    COUNT(DISTINCT t.ID) AS num_groups
FROM
    @tab AS t
WHERE
    t.ID NOT IN
        (SELECT
             t1.ID AS ID1
         FROM
                 @tab AS t1
             INNER JOIN
                 @tab AS t2
             ON
                 t1.ID > t2.ID AND
                 t1.parameter = t2.parameter
         GROUP BY
             t1.ID,
             t2.ID
         HAVING
             COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t1.ID) AND
             COUNT(*) = (SELECT COUNT(*) FROM @tab AS dupe WHERE dupe.ID = t2.ID)
        );

Результат на SQL Server 2008 R2:

num_groups
3

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

1 голос
/ 15 июня 2010

Не существует надежного способа сделать это в SQL Server 2000 с указанными условиями, но в большинстве случаев будет работать следующее, и он предупредит вас, если не будет работать.

Приведенная таблица, " tbl ":

ID  Parameter
 1      A
 1      B
 2      A
 3      A
 3      B
 4      A
 4      NULL
 5      C
 5      D
 6      NULL

.
Создайте эту функцию:

CREATE FUNCTION MakeParameterListFor_tblID (@ID INT)
RETURNS VARCHAR(8000)
AS
BEGIN
    DECLARE
        @ParameterList  VARCHAR(8000),
        @ListLen        INT
    SET
        @ParameterList  = ''

    SELECT
        @ParameterList  = @ParameterList + COALESCE (Parameter, '*null*') + ', '
    FROM
        tbl
    WHERE
        ID  = @ID
    ORDER BY
        Parameter


    SET @ListLen        = LEN (@ParameterList)
    IF  @ListLen > 7800 -- 7800 is a SWAG.
        SET @ParameterList  = '*Caution: overflow!*' + @ParameterList
    ELSE
        SET @ParameterList  = LEFT (@ParameterList, @ListLen-1) -- Kill trailing comma.

    RETURN @ParameterList
END
GO

.
Тогда этот запрос:

SELECT
    COUNT (ID)   AS NumIDs,
    NumParams,
    ParamList
FROM
    (
        SELECT
            ID,
            COUNT (Parameter)                   AS NumParams,
            dbo.MakeParameterListFor_tblID (ID) AS ParamList
        FROM
             tbl
        GROUP BY
            ID
    ) AS ParamsByID
GROUP BY
    ParamsByID.ParamList,
    ParamsByID.NumParams
ORDER BY
    NumIDs      DESC,
    NumParams   DESC,
    ParamList   ASC

.
Даст то, что вы просили.
Результаты:

NumIDs  NumParams   ParamList
  2         2         A, B
  1         2         C, D
  1         1         *null*, A
  1         1         A
  1         0         *null*
0 голосов
/ 20 июля 2010

Я решил проблему с предоставленной ссылкой Cheran S (так как Microsoft SQL Server по-прежнему не имеет функции GROUP_CONCAT ()) http://dataeducation.com/rowset-string-concatenation-which-method-is-best/

0 голосов
/ 12 июня 2010

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

select  count(*)
from    YourTable
group by
        id
having  count(distinct parameter) > 1
...