I want to pass the results of the following query into its own query:
SELECT
'CREATE INDEX [missing_index_'
+ CONVERT (VARCHAR, mig.index_group_handle) + '_'
+ CONVERT (VARCHAR, mid.index_handle) + '_'
+ LEFT (PARSENAME (mid.statement, 1),32) + ']'
+ ' ON ' + mid.statement + ' (' + ISNULL(mid.equality_columns, '')
+
CASE
WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL
THEN ','
ELSE ''
END
+ ISNULL(mid.inequality_columns, '') + ')'
+ ISNULL(' INCLUDE (' + mid.included_columns + ')', '') AS create_index_statement
FROM sys.dm_db_missing_index_groups mig
INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
WHERE
migs.avg_total_user_cost * (migs.avg_user_impact / 100.0)
* (migs.user_seeks + migs.user_scans) > 10
You could concatenate all your rows into a single string, the execute that using sp_executesql
-- BUILD STATEMENT
DECLARE
#SQL NVARCHAR (MAX) = (
SELECT
'CREATE INDEX [missing_index_' + CONVERT (
VARCHAR(MAX)(,
mig.index_group_handle
) + '_' + CONVERT (VARCHAR, mid.index_handle) + '_' + LEFT (
PARSENAME (mid.statement, 1),
32
) + ']' + ' ON ' + mid.statement + ' (' + ISNULL(mid.equality_columns, '') + CASE
WHEN mid.equality_columns IS NOT NULL
AND mid.inequality_columns IS NOT NULL THEN
','
ELSE
''
END + ISNULL(mid.inequality_columns, '') + ')' + ISNULL(
' INCLUDE (' + mid.included_columns + ')',
''
) + ';' AS create_index_statement
FROM
sys.dm_db_missing_index_groups mig
INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
WHERE
migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (
migs.user_seeks + migs.user_scans
) > 10 FOR XML PATH (''),
TYPE ).
VALUE
('.', 'NVARCHAR(MAX)');
-- EXECUTE STATEMENT
EXECUTE sp_executesql #SQL;
HOWEVER I would strongly advise against creating indexes is this manner, it does there are too many other factors to consider when creating indexes, this does not consider a read/write ratio, or lots of similar suggestions that could be amalgamated into one etc. Indexing is as much of an art than it is a science, so I don't think there is a magic fix query that can do this for you.
Related
I am trying to get the total sum from columns of a specific data type(money) for multiple tables in a database. Currently I am able to get the list of columns from specific tables but I am unable to get the sums from those columns.
This is what I have now
use database 1
Select + Column_Name
From information_schema.columns
Where TABLE_NAME = 'claimant'
and data_type = 'money'
The result looks something like below
table_name
column_name
table_1
column_a
table_1
column_b
table_1
column_c
what I would like
table_name
column_name
total_sum
table_1
column_a
66.20
table_1
column_b
300.50
table_1
column_c
5389.42
update for #Squirrel Here is the code I have but it's still giving me issues with truncation.
{
declare #sql nvarchar(max);
select #sql = 'with cte as (' + char(13)
+ 'select' + char(13)
+ string_agg(char(9) + quotename(column_name) + ' = sum(' + quotename(COLUMN_NAME) + ')', ',' + char(13)) + char(13)
+ 'from ' + max(quotename(table_name)) + char(13)
+ ')' + char(13)
+ 'select a.table_name, a.column_name, a.total_sum ' + char(13)
+ 'from cte ' + char(13)
+ 'cross apply (' + char(13)
+ char(9) + 'values' + char(13)
+ string_agg(char(9) + '(''' + table_name + ''',''' + column_name + ''',' + quotename(COLUMN_NAME) + ')', ',' + char(13)) + char(13)
+ ') a (table_name, column_name, total_sum)'
from information_schema.columns AS A
INNER JOIN EDL01.STAGING.TABLE_DETAILS B
ON A.TABLE_NAME = B.DEST_TABLE_NAME
where A.table_name = B.DEST_TABLE_NAME
and data_type = 'money'
print #sql
exec sp_executesql #sql
}
below is the create table
CREATE TABLE [staging].[TABLE_DETAILS](
[SOURCE_TABLE_NAME] [varchar](100) NULL,
[DEST_TABLE_NAME] [varchar](100) NULL,
[TYPE] [varchar](10) NULL,
[PRIORITY] [int] NULL,
[SOURCE_TABLE_DATABASE] [varchar](50) NULL,
[SOURCE_TABLE_SCHEMA] [varchar](50) NULL,
[DEST_TABLE_DATABASE] [varchar](50) NULL,
[DEST_TABLE_SCHEMA] [varchar](50) NULL
) ON [PRIMARY]
GO
Below is part of the results
select a.table_name, a.column_name, a.total_sum
from cte
cross apply (
values
('PAYMENT','BILLEDAMOUNT',[BILLEDAMOUNT]),
('PAYMENT','AMOUNT',[AMOUNT]),
('SIMS_PAYMENT','CHECKAMOUNT',[CHECKAMOUNT]),
('BILLREVIEWHEADER','JURISDICTIONAMOUNT1',[JURISDICTIONAMOUNT1]),
('BILLREVIEWHEADER','JURISDICTIONAMOUNT2',[JURISDICTIONAMOUNT2]),
('BILLREVIE
You need to form the query dynamically and then execute it using sp_executesql or exec()
Note : char(9) is tab, char(13) is carriage return. These are added to format the query so that it is readable when you print it out for verification.
declare #sql nvarchar(max);
select #sql = 'with cte as (' + char(13)
+ 'select' + char(13)
+ string_agg(char(9) + quotename(column_name) + ' = sum(' + quotename(column_name) + ')', ',' + char(13)) + char(13)
+ 'from ' + max(quotename(table_name)) + char(13)
+ ')' + char(13)
+ 'select a.table_name, a.column_name, a.total_sum ' + char(13)
+ 'from cte ' + char(13)
+ 'cross apply (' + char(13)
+ char(9) + 'values' + char(13)
+ string_agg(char(9) + '(''' + table_name + ''', ''' + column_name + ''',' + quotename(column_name) + ')', ',' + char(13)) + char(13)
+ ') a (table_name, column_name, total_sum)'
from information_schema.columns
where table_name = 'table_1'
and data_type = 'money'
print #sql
exec sp_executesql #sql
For your sample table, the generated dynamic query is
with cte as (
select
[column_a] = sum([column_a]),
[column_b] = sum([column_b]),
[column_c] = sum([column_c])
from [table_1]
)
select a.table_name, a.column_name, a.total_sum
from cte
cross apply (
values
('table_1', 'column_a',[column_a]),
('table_1', 'column_b',[column_b]),
('table_1', 'column_c',[column_c])
) a (table_name, column_name, total_sum)
EDIT
using a loop to iterate each table. Basically it execute above query for each of the table and insert the result into a temp table
see db<>fiddle demo
for earlier SQL Server version without string_agg(), use for xml path
select #sql = 'with cte as (' + char(13)
+ 'select' + char(13)
+ stuff
(
(
select ',' + quotename(COLUMN_NAME) + ' = sum(' + quotename(COLUMN_NAME) + ')'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #table
and DATA_TYPE = 'money'
for xml path('')
),
1, 1, ''
) + char(13)
+ 'from ' + max(quotename(#table)) + char(13)
+ ')' + char(13)
+ 'select a.table_name, a.column_name, a.total_sum ' + char(13)
+ 'from cte ' + char(13)
+ 'cross apply (' + char(13)
+ char(9) + 'values' + char(13)
+ stuff
(
(
select ',' + '(''' + TABLE_NAME + ''', ''' + COLUMN_NAME + ''',' + quotename(COLUMN_NAME) + ')'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = #table
and DATA_TYPE = 'money'
for xml path('')
),
1, 1, ''
)
+ ') a (table_name, column_name, total_sum)' + char(13)
Want to set Collation in Select statement in SQL.
I have below SQL query for which I get error :
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AI" in the equal to operation.
I have idea for setting collation for joins, in this case I dont have idea.
Below is the SQL Query for which I am trying to set COLLATE SQL_Latin1_General_CP1_CI_AI,
SET #ColumnNames_CSV_Responses_Smoker_Retail = ' ';
SELECT #ColumnNames_CSV_Responses_Smoker_Retail = COALESCE(#ColumnNames_CSV_Responses_Smoker_Retail, '') +
CASE WHEN QuestionType IN (2, 3, 4)
AND EXISTS (SELECT *
FROM Optiontable
WHERE Option_Code = '1001'
AND Optiontable.Question_ID = Question.QuestionID) THEN 'dbo.ReplaceBrandIDWithCode(''' + CAST(QuestionID AS varchar) + ''',[' + CAST(QuestionID AS varchar) + ']) AS [' + CAST(QuestionID AS varchar) + '],'
WHEN QuestionType IN (3) THEN 'REPLACE(RTRIM(LTRIM([' + CAST(QuestionID AS varchar) + '])),'' '', ''#'') AS [' + CAST(QuestionID AS varchar) + '],'
WHEN QuestionType IN (4) THEN 'REPLACE(REPLACE(SUBSTRING(RTRIM(LTRIM([' + CAST(QuestionID AS varchar) + '])),1, LEN(RTRIM(LTRIM([' + CAST(QuestionID AS varchar) + ']))) - 1),''^'', ''#''),'','','''') AS [' + CAST(QuestionID AS varchar) + '],'
ELSE 'REPLACE(RTRIM(LTRIM([' + CAST(QuestionID AS varchar) + '])),'','', '' '') AS [' + CAST(QuestionID AS varchar) + '],'
END
FROM Question
WHERE CAST(QuestionID AS varchar)IN (SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #Table_Name)
ORDER BY QuestionSeqNumber;
Any Help will be Appreciated, Thanks.
I have a query of the form
SELECT '(''' +
SomeVarCharColumn +
''',' +
CONVERT(NVARCHAR(MAX), SomeIntColumn) +
',' +
CONVERT(NVARCHAR(MAX), SomeOtherIntColumn)
+ ')'
FROM SomeTable
and all the results are NULL. Any idea where I'm going wrong?
null + 1 is null
null + 'things' is null
try this instead:
select '('''
+ isnull(somevarcharcolumn,'')
+ ''','
+ isnull(convert(nvarchar(max), someintcolumn),'null')
+ ','
+ isnull(convert(nvarchar(max), someotherintcolumn),'null')
+ ')'
from sometable
If any column is NULL, then the value is NULL. Use COALESCE():
SELECT '(''' + COALESCE(SomeVarCharColumn, '') + ''',' +
COALESCE(CONVERT(NVARCHAR(MAX), SomeIntColumn), '') + ',' +
COALESCE(CONVERT(NVARCHAR(MAX), SomeOtherIntColumn), '') + ')'
FROM SomeTable
Use the CONCAT() function. When null values are encountered they are simply omitted from the resulting string. Additionally, int to char conversions are implicit no need for the convert, you can find a chart of implicit conversions here https://msdn.microsoft.com/en-us/library/ms187928.aspx
SELECT
CONCAT('(''',SomeVarCharColumn,''',',SomeIntColumn,',',SomeOtherIntColumn,')') AS NewVarchar
FROM SomeTable
What I'm trying to do (the name of the column is passed dynamically, but I hard-coded it, so it seems simpler in this question):
I am trying to query a database using PIVOT tables to sum one field and count the rows of a SQL Server 2012 table, but, in addition, I am trying to retrieve totals to the COUNT() and SUM() functions.
Normally, a pivot table would look like this (which is simpler than what I am trying to reach):
declare #campos nvarchar (max)
select #campos = coalesce(#campos + ',[' + Setor + ']', '[' + Setor + ']')
from dbo.TbFinanciamentos
group by Setor
order by Setor
declare #resultado nvarchar(max)
set #resultado =
'select * from(select Setor, ''br-'' + lower(UF_FILIAL) as [hc-key] from dbo.TbFinanciamentos) a
pivot(
count(Setor)
for Setor in(' + #campos + ')
) a'
execute(#resultado)
But, I wanted to include the total (grand total) as a column, than I followed this tutorial and everything went alright.
What I have so far (that's working):
declare #campos nvarchar (max)
select #campos = coalesce(#campos + ',[' + Setor + ']', '[' + Setor + ']')
from dbo.TbFinanciamentos
group by Setor
order by Setor
declare #total nvarchar(max)
select #total = coalesce(#total + 'isnull([' + Setor + '], 0) + ', 'isnull([' + Setor + '], 0) + ')
from dbo.TbFinanciamentos group by Setor order by Setor
set #total = left(#total, len(#total) - 1)
declare #resultado nvarchar(max)
set #resultado =
'select *, '+ #total +' as [value] into #temp_total
from (select Setor, ''br-'' + lower(UF_FILIAL) as [hc-key] from dbo.TbFinanciamentos) a
pivot(
count(Setor)
for Setor in(' + #campos + ')
) b
select * from #temp_total'
execute(#resultado)
But, as I did for COUNT(), I would like to do for the SUM() and retrieve both in the same query.
What I tried so far to do what I aim to:
I duplicated the PIVOT part and tried to do a FULL OUTER JOIN, but the problem is that it is repeating the columns to the final result what generates an error (Invalid column name). When I print #resultado, there it is, columns are duplicating.
declare #campos nvarchar (max)
select #campos = coalesce(#campos + ',[' + Setor + ']', '[' + Setor + ']')
from dbo.TbFinanciamentos
group by Setor
order by Setor
declare #total nvarchar(max)
select #total = coalesce(#total + 'isnull([' + Setor + '], 0) + ', 'isnull([' + Setor + '], 0) + ')
from dbo.TbFinanciamentos group by Setor order by Setor
set #total = left(#total, len(#total) - 1)
declare #resultado nvarchar(max)
set #resultado =
'select *, '+ #total +' as [value] into #temp_total
from (
(select Setor, ''br-'' + lower(UF_FILIAL) as [hc-key] from dbo.TbFinanciamentos
pivot(
count(Setor)
for Setor in(' + #campos + ')
) as b
) as sth
full outer join
(
select cast(Valor_do_Emprestimo as float) as Valor_do_Emprestimo, Setor, ''br-'' + lower(UF_FILIAL) as [hc-key] from dbo.TbFinanciamentos
pivot(
count(Setor)
for Setor in(' + #campos + ')
) as b
) as sth_else
on sth.[hc-key] = sth_else.[hc-key]
)
select * from #temp_total'
execute(#resultado)
I tried to UNPIVOT and PIVOT method which generates an error of invalid columns as well.
So needless to say doing anything dynamic is highly problematic since you never really get a handle on your metadata. And in any case it's more acceptable when you have multiple conditional aggregations like this to coalesce your different measures using CASE statements, something like
SUM(CASE When Setor = ''' + Setor ''' then 1 else 0 end)
as [' + Setor + '_Count],
SUM(CASE When Setor = ''' + Setor ''' then Valor_do_Emprestimo else 0 end)
as [' + Setor + '_Total],'
and just build up a single query this way against your dataset.
Anyway, to answer your specific issue, if you want to combine these two you have to provide unique column names which means you need to create slightly different versions of #campos and #total. Here I've just done #campos to give you the idea.
Notice I also had to change hc_key to hc_key2 in the second pivot to also avoid duplicate column names.
declare #campos nvarchar (max)
select #campos = coalesce(#campos + ',[' + Setor + ']', '[' + Setor + ']')
from dbo.TbFinanciamentos
group by Setor
order by Setor
declare #campos2 nvarchar (max)
select #campos2 = coalesce(#campos2 + ',[' + Setor + '_2]', '[' + Setor + '_2]')
from dbo.TbFinanciamentos
group by Setor
order by Setor
declare #total nvarchar(max)
select #total = coalesce(#total + 'isnull([' + Setor + '], 0) + ', 'isnull([' + Setor + '], 0) + ')
from dbo.TbFinanciamentos group by Setor order by Setor
set #total = left(#total, len(#total) - 1)
declare #resultado nvarchar(max)
set #resultado =
'select * into #temp_total from (
select *, '+ #total +' as [value] from
(
select * from (select Setor, ''br-'' + lower(UF_FILIAL) as [hc-key] from dbo.TbFinanciamentos) pvt
pivot(
count([Setor])
for Setor in(' + #campos + ')
) as b
) as sth
full outer join
(
select * from (
select * from (select cast(Valor_do_Emprestimo as float) as Valor_do_Emprestimo, Setor+''_2'' as Setor, ''br-'' + lower(UF_FILIAL) as [hc-key2] from dbo.TbFinanciamentos ) pvt
pivot(
sum([Valor_do_Emprestimo])
for Setor in(' + #campos2 + ')
) as b
) c
) as sth_else
on sth.[hc-key] = sth_else.[hc-key2]
) d
select * from #temp_total'
execute(#resultado)
I have a need to create a user table type. My preference is to use a single SQL statement. Ignoring the bells and whistles that can be attributed to such create statement I first derived the logic to generate the create statement for a single column table with the statement:
select 'create type ' + tt.name + ' as TABLE (' + c.name + ' ' + t.name +
case
when t.name in ('varchar','char','nvarchar','nchar','binary','varbinary') then
'(' +
case
when c.max_length = -1 then 'MAX'
else convert(varchar, c.max_length)
end + ')'
when t.name in ('numeric','decimal') then
'(' + convert(varchar, c.precision) + ',' + convert(varchar, c.scale) + ')'
else ''
end + ')'
from sys.table_types tt
join sys.columns c
on tt.type_table_object_id = c.object_id
join sys.types t
on c.system_type_id = t.system_type_id and
c.user_type_id = t.user_type_id
This is limited in scope in terms of the data types, etc but sufficient for now. What I am trying to figure out is out to expand this such that the statement that creates the table column definitions is in some sort of inner loop to handle 1 to n columns. It seems as though it should be possible, but I have not been able to work out the logic.
You can use the for xml path string concatenation trick.
select 'create type ' + tt.name + ' as TABLE (' +
stuff((select ', '+c.name + ' ' + t.name +
case when t.name in ('varchar','char','nvarchar','nchar','binary','varbinary')
then '(' + case when c.max_length = -1
then 'MAX'
else convert(varchar, c.max_length)
end + ')'
when t.name in ('numeric','decimal')
then '(' + convert(varchar, c.precision) + ',' + convert(varchar, c.scale) + ')'
else ''
end
from sys.columns c
inner join sys.types t
on c.system_type_id = t.system_type_id and
c.user_type_id = t.user_type_id
where c.object_id = tt.type_table_object_id
for xml path(''), type
).value('.', 'varchar(max)'), 1, 2, '')+ ')'
from sys.table_types tt