Подсчет записей с указанным условием из списка таблиц в SQLServer (T- SQL) - PullRequest
1 голос
/ 06 апреля 2020

Я пытаюсь добиться чего-то похожего на этот пример PostgreSQL кода, но на SQLServer (T- SQL). Я прикреплю код PG SQL ниже.

Вывод, который я ожидаю, - это список имен таблиц в другой таблице. SELECT table_name FROM dbo.table_list. Этот список также может быть получен из информационной схемы.

Затем я хотел бы count(*) записей в этой таблице с тем же предложением where каждый раз, когда WHERE status = 'CURRENT' это поле присутствует в каждой таблице в этом списке.

Вот пример кода PostgreSQL:

SELECT
table_schema, 
table_name, 
(xpath('/row/cnt/text()' , xml_count))[1]::TEXT::INT AS row_count

FROM (
SELECT 
table_name, 
table_schema, 
query_to_xml(format('SELECT SUM(CASE WHEN status = ''CURRENT'' THEN 1 ELSE 0 END) AS cnt
             FROM %I.%I', table_schema, table_name), false, true, '') AS xml_count
FROM  information_schema.tables
WHERE table_schema =    'my_schema'
  AND table_name   LIKE 'new_%'
) my_fancy_table

Это вывод, который я получаю:

table_schema table_name row_count

------------------- --------------- ------------- -

my_schema new_tt1 1265

my_schema new_tt2 2111

my_schema new_tt3 564589

my_schema new_tt4 9999

my_schema new_tt5 1029 *

В идеале мне бы это понадобилось в такой функции:

CREATE OR REPLACE FUNCTION public.count_currs()
  RETURNS TABLE(a character varying, b character varying, c integer) AS
$BODY$
BEGIN
  RETURN QUERY (SELECT table_schema::VARCHAR, table_name::VARCHAR, (xpath('/row/cnt/text()', xml_count))[1]::text::int FROM ( SELECT table_name, table_schema, query_to_xml(format('select SUM(CASE WHEN status = ''CURRENT'' THEN 1 ELSE 0 END) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count from information_schema.tables where table_schema = 'my_schema' and table_name LIKE 'new_') t) ;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  ROWS 1000;
ALTER FUNCTION public.count_currs()
  OWNER TO postgres;

Так что в моем коде я должен иметь:

SELECT * FROM public.count_currs();

Пожалуйста, извините за подробное объяснение. Я ценю всю помощь!

- РЕДАКТИРОВАТЬ

Как и было запрошено, вы можете использовать это, чтобы создать некоторые данные образца, и я приложу ожидаемый результат. Обратите внимание, что количество таблиц и имена таблиц не установлены и могут быть 1 таблица может быть 1000 таблиц, мне нужно, чтобы это было построено динамически на основе информационной схемы (см. Код выше) или из другой таблицы (см. Код выше). Идея состоит в том, что для каждой таблицы в этом списке возвращаемых таблиц мы выполняем запрос, который будет выполнять что-то вроде этого SELECT COUNT(*) FROM my_schema.table_name WHERE status = 'CURRENT', а затем группировать значения из числа х таблиц в один набор результатов:

Код для создать пример данных:

CREATE SCHEMA [my_schema];

CREATE TABLE [my_schema].[tt1](
    [status] [varchar](100) NULL);

CREATE TABLE [my_schema].[tt2](
    [status] [varchar](100) NULL);

CREATE TABLE [my_schema].[tt3](
    [status] [varchar](100) NULL);

CREATE TABLE [my_schema].[tt4](
    [status] [varchar](100) NULL);

CREATE TABLE [my_schema].[tt5](
    [status] [varchar](100) NULL);


INSERT INTO [my_schema].[tt1] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt1] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt1] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt1] VALUES ('NOT_CURRENT');
INSERT INTO [my_schema].[tt1] VALUES ('NOT_CURRENT');
INSERT INTO [my_schema].[tt1] VALUES ('NOT_CURRENT');


INSERT INTO [my_schema].[tt2] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt2] VALUES ('NOT_CURRENT');

INSERT INTO [my_schema].[tt3] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt3] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt3] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt3] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt3] VALUES ('NOT_CURRENT');
INSERT INTO [my_schema].[tt3] VALUES ('NOT_CURRENT');


INSERT INTO [my_schema].[tt4] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt4] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt4] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt4] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt4] VALUES ('CURRENT');

INSERT INTO [my_schema].[tt5] VALUES ('CURRENT');
INSERT INTO [my_schema].[tt5] VALUES ('NOT_CURRENT');
INSERT INTO [my_schema].[tt5] VALUES ('NOT_CURRENT');
INSERT INTO [my_schema].[tt5] VALUES ('NOT_CURRENT');
INSERT INTO [my_schema].[tt5] VALUES ('NOT_CURRENT');

Тогда я ожидал бы такой результат: Пример вывода

Ответы [ 2 ]

1 голос
/ 06 апреля 2020
Сервер

SQL не имеет аналога query_to_xml и не имеет возможности EXEC -ing динамического c SQL Оператор, созданный как часть того же запроса, за исключением функции CLR.

Функция CLR, приведенная ниже, делает то, что вам нужно (TODO: добавить обработку ошибок), но вы также можете подумать о генерации всего динамического оператора c SQL для доступа ко всем таблицам заранее - или просто выполните отдельные запросы чтобы получить тот же результат.

using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions
{

    [SqlFunction(DataAccess = DataAccessKind.Read)]
    public static SqlInt32 CountRowsWithCurrentStatus(SqlString schemaName, SqlString tableName)
    {
        string quotedSchemaName = string.Format("[{0}]", schemaName.Value.Replace("]", "]]"));
        string quotedTableName = string.Format("[{0}]", tableName.Value.Replace("]", "]]"));

        string query = "SELECT COUNT(*) FROM " + quotedSchemaName + "." + quotedTableName + " WHERE status = 'CURRENT'";

        using (SqlConnection connection = new SqlConnection("context connection=true"))
        {
            connection.Open();
            using (SqlCommand cmd = new SqlCommand(query, connection))
            {
                return new SqlInt32((int)cmd.ExecuteScalar());

            }
        }
    }
}

с тем, что на месте, запрос

SELECT table_name,
       table_schema,
       [dbo].[CountRowsWithCurrentStatus](table_schema, table_name)
FROM   information_schema.tables
WHERE  table_schema = 'my_schema'
       AND table_name LIKE 'tt_%' 
0 голосов
/ 07 апреля 2020

Добрый день,

Если я понимаю вашу потребность и мы можем избежать использования функции, то это простой случай динамического c запроса. Чтобы подтвердить это, проверьте, соответствует ли следующий запрос вашим потребностям. Используйте хранимую процедуру для выполнения кода вместо функции (опять же, при условии, что это соответствует вашим потребностям).

Как вы сказали, у вас есть таблица со списком таблиц (или мы можем использовать системные таблицы по порядку чтобы получить список таблиц), поэтому сначала я его создам - ​​это не является частью решения:

CREATE TABLE table_list (S_Name sysname, T_Name sysname)
GO
INSERT table_list (S_Name, T_Name) values 
('my_schema','tt1'),
('my_schema','tt2'),
('my_schema','tt3'),
('my_schema','tt4'),
('my_schema','tt5')
GO

А теперь мы можем решить ваши потребности с помощью простого динамического c запроса

----------------------------- Solution
DECLARE @query NVARCHAR(MAX)
;With MyCTE AS (
SELECT 
    MyQueryOnSingleTable = 'SELECT ''' + S_Name + ''' as [Schema_name], ''' + T_Name + ''' as [Table_Name]'
    + ', Rows_Counted_as_Current = COUNT(status) FROM ' 
    + QUOTENAME(S_Name) + '.' + QUOTENAME(T_Name)
    + 'WHERE status = ''CURRENT'''
FROM table_list
)
SELECT @query = STRING_AGG(MyQueryOnSingleTable, 'UNION ALL ')
FROM MyCTE

PRINT @query
EXECUTE sp_executesql @query
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...