Ich möchte die 10 besten Datensätze aus jedem Abschnitt in einer Abfrage zurückgeben. Kann mir jemand helfen, wie es geht? Abschnitt ist eine der Spalten in der Tabelle.
Die Datenbank ist SQL Server 2005. Ich möchte die Top 10 nach dem eingegebenen Datum zurückgeben. Die Abschnitte sind geschäftlich, lokal und funktional. Für ein bestimmtes Datum möchte ich nur die obersten (10) Geschäftszeilen (letzter Eintrag), die obersten (10) lokalen Zeilen und die obersten (10) Funktionen.
Wenn Sie SQL 2005 verwenden, können Sie so etwas tun ...
SELECT rs.Field1,rs.Field2
FROM (
SELECT Field1,Field2, Rank()
over (Partition BY Section
ORDER BY RankCriteria DESC ) AS Rank
FROM table
) rs WHERE Rank <= 10
Wenn Ihre RankCriteria gleich ist, geben Sie möglicherweise mehr als 10 Zeilen zurück, und die Lösung von Matt ist möglicherweise besser für Sie.
In T-SQL würde ich Folgendes tun:
WITH TOPTEN AS (
SELECT *, ROW_NUMBER()
over (
PARTITION BY [group_by_field]
order by [prioritise_field]
) AS RowNo
FROM [table_name]
)
SELECT * FROM TOPTEN WHERE RowNo <= 10
Dies funktioniert unter SQL Server 2005 (entsprechend Ihrer Erläuterung bearbeitet):
select *
from Things t
where t.ThingID in (
select top 10 ThingID
from Things tt
where tt.Section = t.Section and tt.ThingDate = @Date
order by tt.DateEntered desc
)
and t.ThingDate = @Date
order by Section, DateEntered desc
SELECT r.*
FROM
(
SELECT
r.*,
ROW_NUMBER() OVER(PARTITION BY r.[SectionID] ORDER BY r.[DateEntered] DESC) rn
FROM [Records] r
) r
WHERE r.rn <= 10
ORDER BY r.[DateEntered] DESC
Ich mache es so:
SELECT a.* FROM articles AS a
LEFT JOIN articles AS a2
ON a.section = a2.section AND a.article_date <= a2.article_date
GROUP BY a.article_id
HAVING COUNT(*) <= 10;
pdate: Dieses Beispiel für GROUP BY funktioniert nur in MySQL und SQLite, da diese Datenbanken in Bezug auf GROUP BY toleranter sind als Standard-SQL. Die meisten SQL-Implementierungen setzen voraus, dass sich alle Spalten in der Auswahlliste, die nicht Teil eines Aggregatausdrucks sind, auch in GROUP BY befinden.
Wenn Sie die Abschnitte kennen, können Sie Folgendes tun:
select top 10 * from table where section=1
union
select top 10 * from table where section=2
union
select top 10 * from table where section=3
Wenn wir SQL Server> = 2005 verwenden, können wir die Aufgabe nur mit einem select lösen:
declare @t table (
Id int ,
Section int,
Moment date
);
insert into @t values
( 1 , 1 , '2014-01-01'),
( 2 , 1 , '2014-01-02'),
( 3 , 1 , '2014-01-03'),
( 4 , 1 , '2014-01-04'),
( 5 , 1 , '2014-01-05'),
( 6 , 2 , '2014-02-06'),
( 7 , 2 , '2014-02-07'),
( 8 , 2 , '2014-02-08'),
( 9 , 2 , '2014-02-09'),
( 10 , 2 , '2014-02-10'),
( 11 , 3 , '2014-03-11'),
( 12 , 3 , '2014-03-12'),
( 13 , 3 , '2014-03-13'),
( 14 , 3 , '2014-03-14'),
( 15 , 3 , '2014-03-15');
-- TWO earliest records in each Section
select top 1 with ties
Id, Section, Moment
from
@t
order by
case when row_number() over(partition by Section order by Moment) <= 2 then 0 else 1 end;
-- THREE earliest records in each Section
select top 1 with ties
Id, Section, Moment
from
@t
order by
case when row_number() over(partition by Section order by Moment) <= 3 then 0 else 1 end;
-- three LATEST records in each Section
select top 1 with ties
Id, Section, Moment
from
@t
order by
case when row_number() over(partition by Section order by Moment desc) <= 3 then 0 else 1 end;
Ich weiß, dass dieser Thread ein bisschen alt ist, aber ich bin gerade auf ein ähnliches Problem gestoßen (wähle den neuesten Artikel aus jeder Kategorie aus) und dies ist die Lösung, die ich mir ausgedacht habe:
WITH [TopCategoryArticles] AS (
SELECT
[ArticleID],
ROW_NUMBER() OVER (
PARTITION BY [ArticleCategoryID]
ORDER BY [ArticleDate] DESC
) AS [Order]
FROM [dbo].[Articles]
)
SELECT [Articles].*
FROM
[TopCategoryArticles] LEFT JOIN
[dbo].[Articles] ON
[TopCategoryArticles].[ArticleID] = [Articles].[ArticleID]
WHERE [TopCategoryArticles].[Order] = 1
Dies ist Darrels Lösung sehr ähnlich, überwindet jedoch das RANK-Problem, das möglicherweise mehr Zeilen als beabsichtigt zurückgibt.
Versuchte Folgendes und es funktionierte auch mit Krawatten.
SELECT rs.Field1,rs.Field2
FROM (
SELECT Field1,Field2, ROW_NUMBER()
OVER (Partition BY Section
ORDER BY RankCriteria DESC ) AS Rank
FROM table
) rs WHERE Rank <= 10
Könnte der Operator UNION für Sie arbeiten? Haben Sie ein SELECT für jeden Abschnitt, und verbinden Sie sie dann miteinander. Ich schätze, es würde nur für eine feste Anzahl von Abschnitten funktionieren.
F) Suchen von TOP X-Datensätzen aus jeder Gruppe (Oracle)
SQL> select * from emp e
2 where e.empno in (select d.empno from emp d
3 where d.deptno=e.deptno and rownum<3)
4 order by deptno
5 ;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7782 CLARK MANAGER 7839 09-JUN-81 2450 10
7839 KING PRESIDENT 17-NOV-81 5000 10
7369 SMITH CLERK 7902 17-DEC-80 800 20
7566 JONES MANAGER 7839 02-APR-81 2975 20
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30
6 Zeilen ausgewählt.
Wenn Sie eine Ausgabe nach Abschnitten gruppieren möchten, werden nur die obersten n Datensätze aus den einzelnen Abschnitten angezeigt.
SECTION SUBSECTION
deer American Elk/Wapiti
deer Chinese Water Deer
dog Cocker Spaniel
dog German Shephard
horse Appaloosa
horse Morgan
... dann sollte das Folgende ziemlich allgemein mit allen SQL-Datenbanken funktionieren. Wenn Sie die Top 10 haben möchten, ändern Sie die 2 gegen Ende der Abfrage in eine 10.
select
x1.section
, x1.subsection
from example x1
where
(
select count(*)
from example x2
where x2.section = x1.section
and x2.subsection <= x1.subsection
) <= 2
order by section, subsection;
So richten Sie ein:
create table example ( id int, section varchar(25), subsection varchar(25) );
insert into example select 0, 'dog', 'Labrador Retriever';
insert into example select 1, 'deer', 'Whitetail';
insert into example select 2, 'horse', 'Morgan';
insert into example select 3, 'horse', 'Tarpan';
insert into example select 4, 'deer', 'Row';
insert into example select 5, 'horse', 'Appaloosa';
insert into example select 6, 'dog', 'German Shephard';
insert into example select 7, 'horse', 'Thoroughbred';
insert into example select 8, 'dog', 'Mutt';
insert into example select 9, 'horse', 'Welara Pony';
insert into example select 10, 'dog', 'Cocker Spaniel';
insert into example select 11, 'deer', 'American Elk/Wapiti';
insert into example select 12, 'horse', 'Shetland Pony';
insert into example select 13, 'deer', 'Chinese Water Deer';
insert into example select 14, 'deer', 'Fallow';
Während die Frage sich auf SQL Server 2005 bezog, sind die meisten Leute weitergegangen. Wenn sie diese Frage finden, ist die bevorzugte Antwort in anderen Situationen eine mit CROSS APPLY
wie in diesem Blogbeitrag dargestellt .
SELECT *
FROM t
CROSS APPLY (
SELECT TOP 10 u.*
FROM u
WHERE u.t_id = t.t_id
ORDER BY u.something DESC
) u
Diese Abfrage umfasst 2 Tabellen. Die OP-Abfrage umfasst nur eine Tabelle, in denen eine auf Fensterfunktionen basierende Lösung möglicherweise effizienter ist.
Sie können diesen Ansatz ausprobieren. Diese Abfrage gibt 10 am dichtesten besiedelte Städte für jedes Land zurück.
SELECT city, country, population
FROM
(SELECT city, country, population,
@country_rank := IF(@current_country = country, @country_rank + 1, 1) AS country_rank,
@current_country := country
FROM cities
ORDER BY country, population DESC
) ranked
WHERE country_rank <= 10;