я могу получить количество () и строки из одного запроса SQL в SQL-сервере?

Я хотел бы получить общее количество результатов и вершины n строки некоторого запроса - действительно ли это возможно в одном операторе?

Я ожидал бы результаты как:

count(..) column1        column2
125         some_value   some_value
125         some_value   some_value

Заранее спасибо!

6
задан Martin Smith 3 March 2011 в 21:25
поделиться

4 ответа

Как это:

SELECT TOP 100 --optional
    MC.Cnt, M.Column1, M.Column2
FROM
    myTable M
    CROSS JOIN
    (SELECT COUNT(*) AS Cnt FROM myTable) MC

Редактировать: После отрицательного голоса и ответа COUNT / OVER. Сравнение двух моих таблиц

Вы можете увидеть огромную разницу между моим CROSS JOIN / простым агрегатом и предложением COUNT / empty ORDER BY

SELECT COUNT(*) OVER() AS C, key1col, key2col
FROM myTable

(24717 row(s) affected)

Table 'Worktable'. Scan count 3, logical reads 49865, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'myTable'. Scan count 1, logical reads 77, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

StmtText
  |--Nested Loops(Inner Join)
       |--Table Spool
       |    |--Segment
       |         |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful]))
       |--Nested Loops(Inner Join, WHERE:((1)))
            |--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1005],0)))
            |    |--Stream Aggregate(DEFINE:([Expr1005]=Count(*)))
            |         |--Table Spool
            |--Table Spool

SELECT
    MC.Cnt, M.key1col, M.key2col
FROM
    myTable M
    CROSS JOIN
    (SELECT COUNT(*) AS Cnt FROM myTable) MC

(24717 row(s) affected)

Table 'myTable'. Scan count 2, logical reads 154, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


StmtText
  |--Nested Loops(Inner Join)
       |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1009],0)))
       |    |--Stream Aggregate(DEFINE:([Expr1009]=Count(*)))
       |         |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful]))
       |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful] AS [M]))

Я повторил это на таблице с 570k строками, и вот IO

Table 'Worktable'. Scan count 3, logical reads 1535456, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'myTable'. Scan count 1, logical reads 2929, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


Table 'myTable'. Scan count 34, logical reads 6438, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
8
ответ дан 8 December 2019 в 13:44
поделиться

Вы можете сделать это с помощью CROSS JOIN и CTE, но это не очень эффективно:

WITH Rows_CTE AS
(
    SELECT Column1, Column2
    FROM Table
    WHERE (...)
)
SELECT c.Cnt, r.Column1, r.Column2
FROM Rows_CTE r
CROSS JOIN (SELECT COUNT(*) AS Cnt FROM Rows_CTE) c

Я думаю, что лучшим способом получить то, что вы хотите, было бы использовать один запрос, но несколько результ-наборов, что вы можете сделать, используя COMPUTE:

SELECT Column1, Column2
FROM Table
WHERE (...)
COMPUTE COUNT([Column1])
3
ответ дан 8 December 2019 в 13:44
поделиться

а как насчет

SELECT COUNT(*) OVER() AS C, COLUMN1, COLUMN2
FROM TABLE  

Что касается CROSS JOIN запросов
в тяжелой INSERT ] / DELETE , перекрестное соединение вернет неверное количество строк.

Попробуйте это для нескольких подключений
подключение 1

set nocount on;
drop table dbo.test_table;
GO
create table dbo.test_table
(
    id_field uniqueidentifier not null default(newid()),
    filler char(2000) not null default('a')
);
GO
create unique clustered index idx_id_fld on dbo.test_table(id_field);
GO
while 1 = 1
insert into dbo.test_table default values;

подключение 2

select T2.cnt, T1.id_field, T1.filler
from dbo.test_table T1
cross join (select COUNT(*) as cnt from dbo.test_table) T2

select T2.cnt, T1.id_field, T1.filler
from dbo.test_table T1
cross join (select COUNT(*) as cnt from dbo.test_table) T2

select T2.cnt, T1.id_field, T1.filler
from dbo.test_table T1
cross join (select COUNT(*) as cnt from dbo.test_table) T2

Каждый раз количество записей ( @@ ROWCOUNT ) отличается от T2.cnt

В случае COUNT (*) OVER () , выполняется только одно сканирование таблицы, а @@ ROWCOUNT всегда совпадает с Т2.cnt

Что касается планов запросов - SQL 2005 SP3, похоже, намного слабее выполняет COUNT (*) OVER () , чем SQL 2008 R2. Кроме того, он неверно сообщает о стоимости запроса (я никогда не думал, что подзапрос может стоить более 100% всего запроса).

Во многих сценариях стоимость COUNT (*) OVER () составляет 50–75% от CROSS JOIN

Наилучший сценарий для перекрестного соединения было бы, если бы был очень узкий индекс, на который можно рассчитывать. Таким образом, будет сканирование кластерного индекса для данных + сканирование индекса для подсчета.

Как всегда, лучше всего измерить, измерить, измерить и пойти на компромисс, с которым вы счастливы жить.

6
ответ дан 8 December 2019 в 13:44
поделиться

попробуйте выполнить этот запрос:

select ColumnId,Descr,(select COUNT(*) from ColumnSetUp)as c
from ColumnSetUp
group by ColumnId,Descr
0
ответ дан 8 December 2019 в 13:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: