2016-04-29 2 views
1

Ich habe Probleme mit einer TSQL-Abfrage und ich bin nicht mehr im Begriff zu googeln, also dachte ich natürlich, ich könnte genauso gut nach SO fragen.Wie wähle ich den häufigsten Wert für einen bestimmten Monat aus und zeige diesen Wert sowie die Häufigkeit an, mit der er auftritt?

Bitte denken Sie daran, dass ich erst vor ein paar Wochen damit begonnen habe, SQL zu lernen, und ich bin mir nicht sicher, welche Regeln es gibt und wie Sie Ihre Abfragen/Unterabfragen schreiben können und müssen.

Dies ist, was ich bisher:

Edit: Aktualisiert mit DDL, die ein Beispiel zu erstellen, auch nicht notwendig, „Client“ -Spalte kommentiert helfen sollen.

CREATE TABLE NumberTable 
(
Number varchar(20), 
Date date 
); 

INSERT INTO NumberTable (Number, Date) 
VALUES 
('55512345', '2015-01-01'), 
('55512345', '2015-01-01'), 
('55512345', '2015-01-01'), 
('55545678', '2015-01-01'), 
('55512345', '2015-02-01'), 
('55523456', '2015-02-01'), 
('55523456', '2015-02-01'), 
('55534567', '2015-03-01'), 
('55534567', '2015-03-01'), 
('55534567', '2015-03-01'), 
('55534567', '2015-03-01'), 
('55545678', '2015-03-01'), 
('55545678', '2015-04-01') 

DECLARE 
    [email protected] AS int, 
    @FromDate AS date, 
    @ToDate AS date 

--SET @ClientNr = 11111 
SET @FromDate = '2015-01-01' 
SET @ToDate = DATEADD(yy, 1, @FromDate) 

SELECT 
    YEAR(Date) AS [Year], 
    MONTH(Date) AS [Month], 
    COUNT(Number) AS [Total Count] 
FROM 
    NumberTable 
WHERE 
    --Client = @ClientNr 
    Date BETWEEN @FromDate AND @ToDate 
    AND Number IS NOT NULL 
    AND Number NOT IN ('888', '144') 
GROUP BY MONTH(Date), YEAR(Date) 
ORDER BY [Year], [Month] 

Damit bekomme ich das Jahr, den Monat und die Gesamtanzahl.

Ich bin glücklich, wenn ich nur die Top 1 der am meisten angerufenen Nummern bekomme und jeden Monat zähle, aber es ist vorzuziehen, die Top 5 zu zeigen.

Heres ein Beispiel dafür, wie ich die Tabelle am Ende aussehen würde (mit den Monaten formatierte Januar, Februar usw. anstelle von Zahlen ist nicht wirklich wichtig, aber würde ein nettes Bonus):

╔══════╦═══════╦═════════════╦═══════════╦══════════╦═══════════╦══════════╗ 
║ Year ║ Month ║ Total Count ║ #1 Called ║ #1 Count ║ #2 Called ║ #2 Count ║ 
╠══════╬═══════╬═════════════╬═══════════╬══════════╬═══════════╬══════════╣ 
║ 2016 ║ JAN ║  80431 ║ 555-12345 ║ 45442 ║ 555-94564 ║ 17866 ║ 
╚══════╩═══════╩═════════════╩═══════════╩══════════╩═══════════╩══════════╝ 

wurde mir gesagt, dieses "leicht" mit einer Unterabfrage erfolgt war, aber ich bin nicht so sicher ...

+0

Wenn SQL Frage zu stellen bitte geben DDL und DML Beispieldaten zu erstellen. Es wird anderen sehr helfen, Ihnen zu helfen. – Serg

+0

@Serg Vielen Dank für den Kopf, ich werde versuchen, meine OP mit einigen nützlichen DDL zu aktualisieren. –

+0

Siehe bearbeitete Antwort – Serg

Antwort

0

artm Abfrage korrigiert (PARTITION) und der letzte Schritt (Pivotieren) vereinfacht.

with data AS 
(select '2016-01-01' as called, '111' as number 
union all select '2016-01-01', '111' 
union all select '2016-01-01', '111' 
union all select '2016-01-01', '222' 
union all select '2016-01-01', '222' 
union all select '2016-01-05', '111' 
union all select '2016-01-05', '222' 
union all select '2016-01-05', '222') 
, ordered AS (
select called 
, number 
, count(*) cnt 
, ROW_NUMBER() OVER (PARTITION BY called ORDER BY COUNT(*) DESC) rnk 
from data 
group by called, number) 
select called, total = sum(cnt) 
, n1= max(case rnk when 1 then number end) 
, cnt1=max(case rnk when 1 then cnt end) 
, n2= max(case rnk when 2 then number end) 
, cnt2=max(case rnk when 2 then cnt end) 
from ordered 
group by called 

EDIT mit dem Setup von OP bereitgestellt

WITH ordered AS(
    -- compute order 
    SELECT 
    [Year] = YEAR(Date) 
    , [Month] = MONTH(Date) 
    , number 
    , COUNT(*) cnt 
    , ROW_NUMBER() OVER (PARTITION BY YEAR(Date), MONTH(Date) ORDER BY COUNT(*) DESC) rnk 
    FROM NumberTable 
    WHERE Date BETWEEN @FromDate AND @ToDate 
     AND Number IS NOT NULL 
     AND Number NOT IN ('888', '144') 
    GROUP BY YEAR(Date), MONTH(Date), number 
) 
-- pivot by order 
SELECT [Year], [Month] 
    , total = sum(cnt) 
    , n1 = MAX(case rnk when 1 then number end) 
    , cnt1 = MAX(case rnk when 1 then cnt end) 
    , n2 = MAX(case rnk when 2 then number end) 
    , cnt2 = MAX(case rnk when 2 then cnt end) 
    -- n3, cnt3, .... 
FROM ordered 
GROUP BY [Year], [Month]; 
+0

Dies scheint den Trick zu tun. Ich muss die Abfrage untersuchen, um sie vollständig zu verstehen, aber nach einem kurzen Test sieht es gut aus. Ich wusste nicht, dass Sie ein CTE so verwenden könnten. –

0

diese Abfrage helfen Ihnen:

IF OBJECT_ID('tempdb..#Test','U') IS NOT NULL DROP TABLE #Test; 

CREATE TABLE #Test(Number INT NOT NULL) 

INSERT INTO #Test(Number) 
VALUES(1),(2),(3),(1) 

SELECT TOP 1 WITH TIES 
    Number 
FROM (
SELECT DISTINCT 
    Number 
    , COUNT(*) OVER(PARTITION BY Number) AS cnt 
FROM #Test) AS T 
ORDER BY cnt DESC 

I TOP 1 WITH TIES verwendet haben für den Fall, dass die maximale Anzahl e xists für mehrere Werte.

1

Interessante man das, glaube ich Sie es mit einem WAK und PIVOT tun können, aber das ist aus der Spitze von meinem Kopf ... Diese Arbeit kann nicht wörtlich

WITH Rollup_CTE 
AS 
(
    SELECT Client,MONTH(Date) as Month, YEAR(Date) as Year, Number, Count(0) as Calls, ROW_NUMBER() OVER (PARTITION BY Client,MONTH(Date) as SqNo, YEAR(Date), Number ORDER BY COUNT(0) DESC) 
    from NumberTable 
     WHERE Number IS NOT NULL AND Number NOT IN ('888', '144') 
    GROUP BY Client,MONTH(Date), YEAR(Date), Number 
) 
SELECT * FROM Rollup_CTE Where SqNo <=5 

Sie können dann in der Lage sein zu verschwenken die Daten, wie Sie diese PIVOT

0

ausprobieren möchten verwenden, müssen nicht CTE sein, aber ich benutzte es, Daten zu füllen, können Sie es 3. aufzunehmen verlängern, 4. usw.

;with data AS 
(select '2016-01-01' as called, '111' as number 
union all select '2016-01-01', '111' 
union all select '2016-01-01', '111' 
union all select '2016-01-01', '222' 
union all select '2016-01-01', '222') 
, ordered AS (
select called 
, number 
, count(*) cnt 
, ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rnk 
from data 
group by called, number) 
SELECT distinct * 
FROM (SELECT DATENAME(month, called) mnth FROM ordered) AS mnth, 
(SELECT number MostCalledNumber FROM ordered WHERE rnk = 1) AS MostCalledNumber, 
(SELECT cnt MostCalledTimes FROM ordered WHERE rnk = 1) AS MostCalledTimes, 
(SELECT number SecondMostCalledNumber FROM ordered WHERE rnk = 2) AS SecondMostCalledNumber, 
(SELECT cnt SecondMostCalledTimes FROM ordered WHERE rnk = 2) AS SecondMostCalledTimes 
Verwandte Themen