Получение количества строк данных - PullRequest
0 голосов
/ 05 февраля 2020

Есть переменная таблицы (здесь я напишу ее как обычную таблицу)

CREATE TABLE TEST (memberid int, producttype varchar(7))

В этой таблице сотни тысяч строк, но для этого примера я добавил намного меньше

Insert into test values(1,'book')
Insert into test values(1,'clothes')
Insert into test values(2,'book')
Insert into test values(3,'book')
Insert into test values(4,'clothes')
Insert into test values(5,'book')
Insert into test values(5,'clothes')
Insert into test values(6,'book')
Insert into test values(7,'book')

Мне нужно получить:

  • членов, которые имеют только «книгу»
  • членов, которые имеют только «одежду»
  • memberids, у которых есть 'book' и 'clothes'

например,

Member     Book      Clothes      Both
  1          0          0           1
  2          1          0           0
  3          1          0           0
  4          0          1           0
  5          0          0           1
  6          1          0           0 
  7          1          0           0

Мне удалось заставить его работать с подзапросами, но из-за размера таблица может занять более 2 минут, чтобы бежать.

Буду признателен, если кто-нибудь знает лучший способ добиться этого?

Ответы [ 3 ]

3 голосов
/ 05 февраля 2020

Используйте CTE для получения, если у каждого участника есть book и / или clothes:

with cte as (
  select memberid,
    count(distinct case when producttype = 'book' then 1 end) book_flag,
    count(distinct case when producttype = 'clothes' then 1 end) clothes_flag
  from test 
  group by memberid
)
select memberid,
  case when book_flag > clothes_flag then 1 else 0 end book,
  case when clothes_flag > book_flag then 1 else 0 end clothes,
  book_flag * clothes_flag both
from cte

См. Демоверсию . Результаты:

> memberid | book | clothes | both
> -------: | ---: | ------: | ---:
>        1 |    0 |       0 |    1
>        2 |    1 |       0 |    0
>        3 |    1 |       0 |    0
>        4 |    0 |       1 |    0
>        5 |    0 |       0 |    1
>        6 |    1 |       0 |    0
>        7 |    1 |       0 |    0
3 голосов
/ 05 февраля 2020

В одном методе используется условное агрегирование:

select 
    memberid,
    case when max(producttype) = 'book' then 1 else 0 end book,
    case when min(producttype) = 'clothes' then 1 else 0 end clothes,
    case when min(producttype) <> max(producttype) then 1 else 0 end both
from test
group by memberid

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

case when count(*) = sum(case when producttype = 'book' then 1 end)
    then 1
    else 0
end book
2 голосов
/ 05 февраля 2020

Переменная таблицы с сотнями тысяч строк будет проблематичной c для вас.

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

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

CREATE TABLE #TEST (memberid int, producttype varchar(7));

CREATE NONCLUSTERED INDEX tempTest ON #TEST(producttype);
...