2016-04-15 5 views
0

У меня есть следующий запрос:SQL Server HAVING COUNT OVER выпуска

SELECT DISTINCT 
    x.CountryID [code], 
    c.Description [name], 
    COUNT(x.username) OVER(PARTITION BY x.countryID) [count], 
    COUNT(x.username) OVER() [tcount], 
    COALESCE(c.Map,'world') [map] 
FROM 
(
    SELECT DISTINCT 
     CountryID, 
     username, 
     Score 
    FROM global.dbo.UserCategories 
    WHERE TLCID LIKE @TLCID OR TLCID IN (@TLCID) 
) x 
JOIN global.dbo.countrydetails c on x.CountryID=c.country 
AND x.Score BETWEEN @ScoreMin AND @ScoreMax 
GROUP BY x.CountryID, c.Description, c.Map, x.username --WITH ROLLUP 
--HAVING COUNT(x.username) OVER(PARTITION BY x.countryID)>@Min 
ORDER BY [name] ASC 

, который показывает для каждой страны количества пользователей, имеющих определенный балл и активный в определенных категориях Я хотел бы исключить из стран списка с несколько пользователей , и я думал, чтобы добавить предложения HAVING но SQL говорит мне

«Windowed функции могут появляться только в SELECT, или ORDER BY статей.»

самая важная таблица CountryDetails, что выглядит следующим образом:

CountryID username score  TLCID 
    DE  12-bu  19598  131090 
    DE  12-bu  19598  220 
    DE  12-bu  19598  11700 
    DE  12-bu  19598  131090 
    DE  1buy3  19648  11700 
    DE  1buy3  19648  11450 
    DE  1buy3  19648  11700 
    DE  1buy3  19648  11700 
    CN  2012f  22780  11450 
    CN  2012f  22780  11450 
    CN  2012f  22780  11450 
    CN  2012f  22780  11450 
    CN  2012f  22780  11450 
    GB  agood  74539  1 
    GB  agood  74539  11450 
    GB  agood  74539  12576 
    GB  agood  74539  131090 
    GB  agood  74539  1 
    GB  agood  74539  11233 
    GB  agood  74539  1 
    GB  agood  74539  1 
    GB  agood  74539  1 
    GB  agood  74539  220 
    BG  best0  3173  2984 
    IT  bestb  13777  15032 
    IT  bestb  13777  293 
    IT  bestb  13777  293 
    IT  bestb  13777  15032 
    IT  bestb  13777  15032 
    IT  bestb  13777  15032 
    IT  bestb  13777  58058 
    IT  bestb  13777  293 
    DE  bestb  55165  131090 
    DE  bestb  55165  293 
    DE  bestb  55165  293 
    DE  bestb  55165  293 
    DE  bestb  55165  293 
    CN  besto  24537  11450 
    GB  bidan  4584  58058 
    GB  bidan  4584  58058 
    IT  bimbu  4145  11700 
    GB  buy_d  97093  12576 
    GB  buy_d  97093  888 
    GB  buy_d  97093  888 
    GB  buy_d  97093  888 
    GB  buy_d  97093  159912 
    GB  buy_d  97093  888 
    GB  buy_d  97093  159912 
    GB  buy_d  97093  11700 
    GB  buy_d  97093  11700 
    GB  buy_d  97093  159912 
    GB  buy_d  97093  20710 
    GB  buy_d  97093  159912 
    GB  buy_d  97093  888 
    GB  buy_s  988538  11232 
    GB  buy_s  988538  1 
    GB  buy_s  988538  11700 
    GB  buy_s  988538  26395 

относительно результата .. теперь я получаю это

code name  count  tcount map 
AD  Andorra   3  83141 andorra 
AU  Australia  14  83141 australia 
AT  Austria   345  83141 austria 
..... 
BE  Belgium   28  83141 belgium 
CN  China   1070 83141 china 
FR  France   4732 83141 france 
DE  Germany   33782 83141 germany 
HK  Hong Kong  364  83141 hongKong 
HU  Hungary   9  83141 hungary 
..... 
IN  India   10  83141 india 
IR  Iran   1  83141 iran 
IQ  Iraq   17  83141 iraq 
IE  Ireland   36  83141 ireland 
IL  Israel   16  83141 israel 
IT  Italy   5427 83141 italy 
JE  Jersey   25  83141 world 
.... 
GB  United Kingdom 35136 83141 unitedKingdom 

....

предполагая установить @Min to 20 Я хочу это получить:

code name   count tcount map 
AT  Austria   345  80945 austria 
BE  Belgium   28  80945 belgium 
CN  China   1070 80945 china 
FR  France   4732 80945 france 
DE  Germany   33782 80945 germany 
HK  Hong Kong  364  80945 hongKong 
IE  Ireland   36  80945 ireland 
IT  Italy   5427 80945 italy 
JE  Jersey   25  80945 world 
GB  United Kingdom 35136 80945 unitedKingdom 

где tcount - сумма отчётов

Может ли Pls предложить путь для обхода?

Спасибо!

+1

Вы пробовали 'HAVING [число]> @ Min'? Не уверен, хотя, не могу попробовать это сам прямо сейчас. –

+0

Да, пробовал, но (я полагаю), поскольку [count] - это вычисленные поля внутри запроса, не может использоваться как параметр – Joe

+0

Так как в группе GROUP BY появляется 'x.CountryId', вам не нужно разделять. HAVING работает на том же уровне, что и группа. В этом случае он будет подсчитывать количество записей в уникальных комбинациях 'CountryId, Description, Map, Username'. –

ответ

1

вы могли бы сделать что-то же просто, как это ..

SELECT c.countryid, 
     c.[description], 
     x.[count], 
     SUM([count]) OVER() [tcount], 
     COALESCE(c.Map,'world') [map] 
FROM global.dbo.countrydetails c 
     OUTER APPLY (
      SELECT COUNT(DISTINCT uc.username) [count] 
      FROM global.dbo.UserCategories uc 
      WHERE uc.countryid = c.countryid 
        AND TLCID LIKE @TLCID OR TLCID IN (@TLCID) 
        AND uc.Score BETWEEN @ScoreMin AND @ScoreMax 
     ) x 
WHERE x.[count] > @Min 

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

SQL Fiddle

+0

hmmm .. да .. кажется, что (снова!) наружное применение является решением .. проведет еще один тест и дайте знать! – Joe

+0

'Cross Apply 'может дать вам лучшие результаты, так как вы фильтруете результаты в' Where', поэтому я бы попробовал оба – JamieD77

0

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

Это должно быть довольно близко.

SELECT DISTINCT 
    x.CountryID [code], 
    c.Description [name], 
    COUNT(x.username) as [tcount], 
    COALESCE(c.Map,'world') [map] 
FROM 
(
    SELECT DISTINCT 
     CountryID, 
     username, 
     Score 
    FROM global.dbo.UserCategories 
    WHERE TLCID = @TLCID 
) x 
JOIN global.dbo.countrydetails c on x.CountryID=c.country 
AND x.Score BETWEEN @ScoreMin AND @ScoreMax 
GROUP BY x.CountryID, c.Description, c.Map 
HAVING COUNT(x.username) > @Min 
ORDER BY [name] ASC 

--EDIT--

Это сложно понять, что вы хотите, потому что у нас нет никаких таблиц, данные примеры и не желаемых результатов. Короче говоря, самое лучшее, что может сделать каждый сейчас, это угадать, что вы можете захотеть. Это хорошая статья, в которой объясняется, что вы должны публиковать для помощи t-sql на онлайн-форумах. http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/

Вот еще одна догадка о том, что вы, возможно, захотите. Я заметил, что у вас есть отчетливые и групповые. Это избыточно.

with CompiledValues as 
(
    SELECT x.CountryID as [code], 
     c.Description as [name], 
     COUNT(x.username) OVER(PARTITION BY x.countryID) as [count], 
     COUNT(x.username) OVER() as [tcount], 
     COALESCE(c.Map,'world') [map] 
    FROM 
    (
     SELECT DISTINCT 
      CountryID, 
      username 
     FROM global.dbo.UserCategories 
     WHERE TLCID = @TLCID 
    ) x 
    JOIN global.dbo.countrydetails c on x.CountryID = c.country 
     AND x.Score BETWEEN @ScoreMin AND @ScoreMax 
    GROUP BY x.CountryID 
     , c.Description 
     , c.Map 
) 

select * 
from CompiledValues 
where tcount > @Min 
ORDER BY [name] ASC 
+0

Привет, Шон, спасибо за ответ, да, это решает проблему HAVING, но вы удалили мне поле [tcount] (вы переименовали [count] в [tcount]). в [tcount] у меня было общее число пользователей всех стран, и я не могу дождаться окончания цикла для вычисления, так как мне нужно знать заранее, так как он используется для некоторых вычислений – Joe

+0

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

0

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

-- Filtering by Count of CountryID, username, Score 
SELECT DISTINCT 
    x.CountryID [code], 
    c.Description [name], 
    COUNT(x.username) OVER(PARTITION BY x.countryID) [count], 
    COUNT(x.username) OVER() [tcount], 
    COALESCE(c.Map,'world') [map] 
FROM 
(
    SELECT COUNT(*), 
     CountryID, 
     username, 
     Score 
    FROM global.dbo.UserCategories 
    WHERE TLCID LIKE @TLCID OR TLCID IN (@TLCID) 
    GROUP BY CountryID, 
     username, 
     Score 
    HAVING COUNT(*) > [Your_Threshold_Number] 
) x 
JOIN global.dbo.countrydetails c on x.CountryID=c.country 
AND x.Score BETWEEN @ScoreMin AND @ScoreMax 
GROUP BY x.CountryID, c.Description, c.Map, x.username 
ORDER BY [name] ASC 

-- Filtering by Count of CountryID, username 
SELECT DISTINCT 
    x.CountryID [code], 
    c.Description [name], 
    COUNT(x.username) OVER(PARTITION BY x.countryID) [count], 
    COUNT(x.username) OVER() [tcount], 
    COALESCE(c.Map,'world') [map] 
FROM 
(
    SELECT COUNT(*), 
     CountryID, 
     username, 
     Score 
    FROM global.dbo.UserCategories AS g1 
    JOIN (SELECT COUNT(*) AS Cnt, 
     CountryID, 
     username 
    FROM global.dbo.UserCategories 
    GROUP BY CountryID, 
     username 
    HAVING COUNT(*) > [Your_Threshold_Number] 
    ) g2 ON g1.CountryID = g2.CountryID 
    WHERE TLCID LIKE @TLCID OR TLCID IN (@TLCID) 
    GROUP BY CountryID, 
     username, 
     Score 
) x 
JOIN global.dbo.countrydetails c on x.CountryID=c.country 
AND x.Score BETWEEN @ScoreMin AND @ScoreMax 
GROUP BY x.CountryID, c.Description, c.Map, x.username 
ORDER BY [name] ASC