I need run a generic SQL query with the character # between each field in the query result so that I can work with in Excel. I.E:
SELECT * FROM EMPLOYEE
RESULT
NAME#AGE#SALARY#EMAIL
Bob#59#1700#bob#bob.com
How can I to do this?
In Caché you can export data with System Management Portal. You can read how you can do it in the documentation.
SELECT Name + '#' + AGE FROM Employee
Or you may need to convert some fields, in MSSQL it looks like:
SELECT (CONVERT(VARCHAR(255), E.Age) + '#')
FROM Employee E
If you cannot specify values:
DECLARE #tableName VARCHAR(255) = 'Employee'
-- use MAX since this will be a long query
DECLARE #csv VARCHAR(MAX)
-- Create a query containing SELECT CONVERT(varchar(255), COALESCE(columnanme, '')) for all column names, in 1 line
-- COALACE in case a column is null (otherwise result will be 'null'.
SELECT #csv = COALESCE(#csv + 'CONVERT(VARCHAR(255),COALESCE(' + SC.name + ', '''')) + ''#'' + ', '')
FROM sysobjects SO
JOIN syscolumns SC ON SC.id = SO.id
WHERE SO.name = #tableName
-- chop off the last ','
SET #csv = (SELECT LEFT(#csv, LEN(#csv) -1))
SET #csv = 'SELECT ' + #csv + ' FROM ' + #tableName
-- for debugging:
-- SELECT #csv
-- execute the SQL query
EXEC #csv
Edit for MSSQL, 'EXEC' will truncate the #csv variable, if this is the case you'll have to use 2 variables (or more if #csv is longer than 2000)
DECLARE #csvPartOne VARCHAR(500) = LEFT(#csv, 500)
DECLARE #csvPartTwo VARCHAR(MAX) = RIGHT(#csv, LEN(#csv) - 500)
-- execute the SQL query
EXEC (#csvPartOne + #csvPartTwo)
Related
So simply I'm doing something similar to:
select
[BadData], [WorseDate], [IQuitData]
into
#BadDataTempTable
from
SomeoneElsesMess
what I want to do now is something similar to:
Select
Replace(#BadDataTempTable.*, ',', ' ')
from
#BadDataTempTable -- Replace all commas in every column `with a space--`
Is this possible? If so please show me the easiest (non-function) way to do so.
Thanks. SQL Server 2012 I think. I'm using SSMS 17
No, the columns have to be specified. You could use dynamic SQL to build your update / query. Then just copy the command you want from the results.
Maybe this will help get you started:
BEGIN
-- Set the replace value
DECLARE #ls_replaceValue NVARCHAR(MAX) = ',';
-- Set the with value
DECLARE #ls_withValue NVARCHAR(MAX) = ' ';
-- Set the table name we want to query
DECLARE #ls_table NVARCHAR(MAX) = 'some_table';
-- Get all of the columns and provide the replace parameters
DECLARE #ls_columns NVARCHAR(MAX) = '';
SELECT #ls_columns = #ls_columns + ', ' + name + ' = REPLACE(' + name + ', ' + '' + '''' + REPLACE(#ls_replaceValue, '''', '''''''') + '''' + ', ' + '''' + REPLACE(#ls_withValue, '''', '''''''') + '''' + ')'
FROM sys.all_columns
WHERE object_id = OBJECT_ID(#ls_table)
AND collation_name IS NOT NULL; -- Skip columns that aren't character based
-- Remove the first ', ' from the column list
SET #ls_columns = SUBSTRING(#ls_columns, 3, LEN(#ls_columns));
IF #ls_columns = ''
BEGIN
PRINT 'Table not found'
RETURN
END
-- Build a query
DECLARE #ls_query_sql NVARCHAR(MAX) = '';
SET #ls_query_sql = 'SELECT ' + #ls_columns + ' FROM ' + #ls_table;
-- Show the results
SELECT #ls_query_sql AS querySQL;
END
Just since the OP asked about how you might do this in dynamic SQL, here's how I'd approach it. Basically get the table schema information and concatenate all the columns, plus the REPLACE logic you want using FOR XML. This basically constructs the statement Rigerta posted, but does it dynamically.
use tempdb
go
if object_id('tempdb.dbo.#SomeoneElsesBadData') is not null drop table #SomeoneElsesBadData
create table #SomeoneElsesBadData
(
BadData varchar(250),
WorseData varchar(250),
IQuitData varchar(250)
)
declare #sql nvarchar(max)
select #sql = 'select '
+ stuff((select ', '
+ name
+ ' = replace(' + name + ''','', '''')'
from tempdb.sys.columns
where object_id = object_id('tempdb.dbo.#SomeoneElsesBadData')
for xml path('')), 1, 1, '')
+ ' into #BadDataTempTable
from #SomeoneElsesBadData'
exec sp_executesql #sql
All things being equal, the data should probably be cleaned before it gets into SQL, but reality is rarely fair.
I want to know how can I use the information_schema_tables select query to look up #tablename, so that, that table's catalog and schema is shown, and then concatenate it together so that #tablename is displayed as table_catalog.table_schema.table name'?
At the moment I am just calling on the table name using select #tablename = Value
declare #tablename varchar(MAX)
declare #tableschema varchar(MAX)
declare #loop int = 1
select a.* into #tmp
from
(
select RID,
v.value('local-name(.)', 'VARCHAR(MAX)') 'Field',
v.value('./text()[1]', 'VARCHAR(MAX)') 'Value'
from #XMLTemp
cross apply Field.nodes ('/Record/*') x(v)
where v.value('local-name(.)', 'VARCHAR(MAX)') not in ('Update', 'Filter', 'Insert', 'Delete')
) as a
where RID = #loop
...
select Table_Catalog, Table_Schema
from Information_Schema.Tables
...
select #tablename = ''
select #tablename = Value
from #tmp
where Field='tableName'
and RID = #loop
...
print 'update ' + #tablename + '
...
select #tablename = Value from #tmp where Field = 'TableName'
...
set #loop = #loop+1
In SQL Server you can use "+" to concatenate strings.
declare #tablename varchar(MAX)
select #tablename = TABLE_CATALOG + '.' + TABLE_SCHEMA + '.' + TABLE_NAME
from INFORMATION_SCHEMA.TABLES
where TABLE_NAME = 'TableName'
Keep in mind that if your query returns multiple rows #tablename variable will contains the last value returned.
select quotename(db_name()) + '.' + quotename( schemas.name ) + '.' + quotename( tables.name )
from sys.tables
join sys.schemas on tables.schema_id = schemas.schema_id
A couple of notes: "Catalog" in ANSI speak is Database in SQL Server, so within a database it's pretty much a constant value - the name of the current database.
In SQL Server I find the system views are more consistent and reliable than INFORMATION_SCHEMA, which mostly works but has some quirky issues.
According to your last question I'd like to suggest the following UDF:
You pass in your XML and a catalog's name (or NULLor DEFAULT) and the same with the schema's name. The function will use COALESCE to use the right portion:
CREATE FUNCTION dbo.CreateUpdateStatement
(
#XmlData XML
,#CatalogName VARCHAR(100) = NULL
,#SchemaName VARCHAR(100) = NULL
)
RETURNS VARCHAR(MAX)
BEGIN
DECLARE #RetVal VARCHAR(MAX);
WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' AS xsi)
SELECT #RetVal=
'UPDATE '
+ COALESCE(#CatalogName + '.',TheTable.TABLE_CATALOG + '.', '')
+ COALESCE(#SchemaName + '.',TheTable.TABLE_SCHEMA + '.', 'dbo.')
+ One.Record.value('TableName[1]','varchar(max)')
+ ' SET ' + One.Record.value('(Update/FieldName)[1]','varchar(max)') + '=''' + One.Record.value('(Update/NewValue)[1]','varchar(max)') + ''' '
+ ' WHERE ' + One.Record.value('KeyField[1]','varchar(max)') + '=''' + One.Record.value('TableRef[1]','varchar(max)') + ''';'
FROM #XmlData.nodes('/Task/Record') AS One(Record)
OUTER APPLY
(
SELECT TOP 1 TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME=One.Record.value('TableName[1]','varchar(max)')
) AS TheTable;
RETURN #RetVal;
END
GO
This is how you call it (I used one existing table's name spz.dbo.AuditRow in one of my catalogs):
DECLARE #x xml=
'<Task xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Record>
<order>1</order>
<TableName>AuditRow</TableName>
<KeyField>ProductPersonID</KeyField>
<TableRef>32420</TableRef>
<Update>
<FieldName>StatusID</FieldName>
<OldValue>3</OldValue>
<NewValue>8</NewValue>
</Update>
</Record>
</Task>';
SELECT dbo.CreateUpdateStatement(#x,DEFAULT,DEFAULT);
--UPDATE spz.dbo.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
SELECT dbo.CreateUpdateStatement(#x,'MyCatalog',DEFAULT);
--UPDATE MyCatalog.dbo.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
SELECT dbo.CreateUpdateStatement(#x,DEFAULT,'MySchema');
--UPDATE spz.MySchema.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
SELECT dbo.CreateUpdateStatement(#x,'MyCatalog','MySchema');
--UPDATE MyCatalog.MySchema.AuditRow SET StatusID='8' WHERE ProductPersonID='32420';
You might execute this immediately with
EXEC (SELECT dbo.CreateUpdateStatement(#x,NULL,NULL));
I have multiple columns with some amount in a table and I want to show the total of all those amounts in the last Total column. I have a table in sql which looks somewhat like this,
A_Amt B_Amt C_Amt D_Amt E_Amt F_Amt ...
------------------------------------------------
15 20 25 30 35 40
i have written a query as
declare #xmlResult xml=
(
select *
from Foo
for xml PATH
);
SELECT Nodes.node.value('sum(*[contains(local-name(.), "_Amt")])', 'decimal(15,2)') AS Total
FROM
#xmlResult.nodes('//row') as Nodes(node);
but the result I am getting has only one column total but i want all the columns in resultant table like A_amt etc..
This should be what you need, BUT ATTENTION! You should NOT do this. Aggregate rows should NEVER be fetched together with the "raw" data. This is - in most cases - something your UI should do (or a report...)
declare #table TABLE(ID INT IDENTITY, a INT,b INT,c INT);
insert into #table VALUES(1,1,1),(2,3,4),(5,6,7);
SELECT a,b,c
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY t.ID) AS inx
,a,b,c
FROM #table AS t
UNION SELECT 999999,SUM(a),SUM(b),SUM(c)
FROM #table
) AS tbl
ORDER BY tbl.inx
I think this is what you are looking for, try this (replace spt_values with your table) :
USE MASTER
GO
declare #lsql nvarchar(max)
declare #lsql2 nvarchar(max)
declare #yourTable nvarchar(255) = 'spt_values'
Select #lsql = isnull(#lsql+'+','') + 'Case When ISNUMERIC('+name+') = 1 Then '+name+' else 0 end' from sys.Columns where Object_id = Object_id(#yourTable)
Print #lsql
SET #lsql2 = 'Select *, '+#lsql+' as Total_allcolumns From '+#yourTable+''
Exec(#lsql2)
Using Microsoft's system table is one way to achieve dynamic SQL and thus your goal. The code below is what you want or will at least get you started.
I wasn't sure what output you expected, so I included two outputs. Just use the one you want and discard the other one. Given your question, it is probably result1. (Result1 or Result2)
!!You have to write the table name in the script at the place indicated prior to executing it!!
--DISCLAIMER
--It assume you use SQL SERVER 2012. (Probably work on 2005+ with little adjustment)
--It assume data is in a table, (Not a view for example)
--Changing SQL SERVER version may break the code as Microsoft could change "system views".
--I don't remember well, but EXEC may be limited to 4000 characters in dynamic query. (But there is a work around, just look around if you need it)
--So use at your own risk
DECLARE #objectIDTable INT,
#AllColumnAdditionStatement NVARCHAR(MAX) = '',
#TableName NVARCHAR(250) = 'WriteYourTableNameHere',--!!!OVERWRITE THE TABLE NAME HERE
#Query NVARCHAR(MAX),
#AllSumStatement NVARCHAR(MAX) = ''
SELECT TOP 1 #objectIDTable = [object_id],
#AllColumnAdditionStatement = ''
FROM sys.objects
WHERE type_desc = 'USER_TABLE'
AND name = #TableName
SELECT #AllColumnAdditionStatement = #AllColumnAdditionStatement + 'CONVERT(DECIMAL(18, 4), (CASE WHEN ISNUMERIC(' + name + ') = 1 THEN ISNULL(' + name + ', ''0'') ELSE 0 END))' + ' + ',
#AllSumStatement = #AllSumStatement + name + 'Total = SUM(CONVERT(DECIMAL(18, 4), (CASE WHEN ISNUMERIC(' + name + ') = 1 THEN ISNULL(' + name + ', ''0'') ELSE 0 END))), ' + CHAR(10)
FROM sys.columns
WHERE object_id = #objectIDTable
AND name LIKE '%_Amt' --!!!Here is a column filter/selector to sum only column ending with _Amt
SELECT #AllColumnAdditionStatement = #AllColumnAdditionStatement + '0', --just too lazy to chop off last three char
#AllSumStatement = #AllSumStatement + 'Total_ = SUM(' + #AllColumnAdditionStatement + ')' + CHAR(10),
#Query = 'SELECT *,
Total_ = ' + #AllColumnAdditionStatement +'
FROM ' + #TableName
PRINT (#Query)
/********************************************************************************************/
EXEC (#Query) --or use sp_execute if you prefer
--Result1 : addition of all selected columns into total column with all column return as well
/********************************************************************************************/
SELECT #Query = 'SELECT ' + #AllSumStatement + '
FROM ' + #TableName
EXEC (#Query) --or use sp_execute if you prefer
--Result2 : Summation of all column individualy and summation of all of them into total column
/********************************************************************************************/
I need to create a report that shows all of the SSRS (rdl) indicating what databases the reports use. I have used sys.databases and the rdl content to create a table showing all of the reports with database names as column names. (Client has over 100 databases.) If a database was found within the rdl code I indicated it with an 'X'.
Here is an example:
Report Name tempdb Master Test Reports Claims
My Report.rdl X
Ur Report.rdl X X
Master.rdl X
Currently I am doing a while loop through the sys.databases and creating a dynamic SQL statement like this:
...
Declare variables
Set #SQLStatement equal to the beginning of the select with static columns
...
While Loop
SET #ColumnsSqlStatement = 'SELECT #Result = Count(*)
from ##DatabasesUsed where ['
+ #NAME + '] = ''X'''
EXEC sp_executesql #ColumnsSqlStatement, N'#Result int out',
#NumberOfXs OUT
IF #NumberOfXs > 0
BEGIN
SET #SQLStatement = #SQLStatement + ', DBU.['
+ LTRIM(RTRIM(#NAME)) + ']'
END
End Loop
I then execute #SQLStatement which returns only the columns with data.
Report Name tempdb Test Reports
My Report.rdl X
Ur Report.rdl X X
Master.rdl X
I am looking for a set based solution to get rid of the while loop. Something like this:
SELECT E.Name AS [Database],
(
SELECT Count(*) FROM ##DatabasesUsed WHERE [E.Name] = 'X'
) AS [counts]
FROM sys.databases E
Obviously this doesn't work but what I need is for the select to convert the E.Name to the value of E.Name.
I appreciate any help. Maybe there is a completely different solution to my problem.
Thanks.
Try this...I am using all temporary tables so you'll need to retrofit some of it to match your database tables (you should be able to copy and paste this and have it run just fine though for testing or whatever). I have a few debugging SELECT statements in there too just to show the output along the way. I hope that this helps!
IF OBJECT_ID('tempDB..#DBsUsed') IS NOT NULL
DROP TABLE #DBsUsed
CREATE TABLE #DBsUsed (REPORT_NAME VARCHAR(50), tempDb VARCHAR, [Master] VARCHAR, Test VARCHAR, Reports VARCHAR, Claims VARCHAR)
INSERT INTO #DBsUsed (REPORT_NAME, tempDb, Master, Test, Reports, Claims)
VALUES
('My Report.rdl', 'X', '', '', '', ''),
('Your Report.rdl', '', '', 'X', 'X', ''),
('Master.rdl', '', '', '', 'X', '')
SELECT *
FROM #DBsUsed
IF OBJECT_ID('tempDB..#Temp_Columns') IS NOT NULL
DROP TABLE #Temp_Columns
CREATE TABLE #Temp_Columns (COLUMN_NAME VARCHAR(50), HasData INT, SQLCommand VARCHAR(MAX))
INSERT INTO #Temp_Columns (COLUMN_NAME, HasData, SQLCommand)
SELECT name, NULL, 'WHEN ''' + name + ''' THEN (SELECT COUNT(*) FROM #DBsUsed WHERE ' + name + '=''X'')'
FROM tempDB.sys.columns
WHERE [object_id] = OBJECT_ID('tempDB..#DBsUsed')
AND name <> 'REPORT_NAME'
SELECT *
FROM #Temp_Columns;
DECLARE #MasterCommand VARCHAR(MAX) = ( 'UPDATE #Temp_Columns SET HasData = CASE COLUMN_NAME ' + (SELECT SQLCommand + ' ' FROM #Temp_Columns FOR XML PATH('')) + ' END')
EXEC (#MasterCommand)
SELECT *
FROM #Temp_Columns
DELETE FROM #Temp_Columns
WHERE HasData = 0
DECLARE #ColumnList VARCHAR(MAX), #FinalSelect VARCHAR(MAX)
SET #ColumnList = (SELECT COLUMN_NAME + ',' FROM #Temp_Columns FOR XML PATH (''))
SET #ColumnList = LEFT(#ColumnList, LEN(#ColumnList) - 1)
SET #FinalSelect = 'SELECT ' + #ColumnList + ' FROM #DBsUsed'
EXEC (#FinalSelect)
The last line (EXEC (#FinalSelect)) should get you the output that you are looking for.
Suppose you have a table like this:
ID FNAME LNAME
1 Bob Smith
2 Sally Jones
A simple SELECT * FROM [Table] will return all rows. But what if you wanted to build a single string out of the results, and the column names are unknown? In other words, this will not work:
SELECT ID + ',' + FNAME + ',' + LNAME FROM [Table]
because you don't know the column names. Additionally, COALESCE won't work because it doesn't accept wildcards. Ideally you want to execute something like this:
SELECT dbo.FunctionThatSplitsResultsToString(*) FROM [Table]
and have it return
1,Bob,Smith
2,Sally,Jones
Is this possible?
This is a corrected version of the answer #Igor gave. In addition to concatenating comma characters between the values, it converts NULL values to an empty string (because concatenating a string to NULL results in a NULL value).
DECLARE #sql NVARCHAR(max)='SELECT '
DECLARE #TableName NVARCHAR(max) = 'Table_Name' -- <-- Set the target table name here
SELECT #sql=#sql+N'ISNULL(CAST(' + name +' as NVARCHAR(max)), '''')+'',''+'
FROM sys.columns
WHERE object_id=OBJECT_ID(#TableName)
SELECT #sql=SUBSTRING(#sql,1,LEN(#sql)-5)+N' FROM ' + #TableName
--SELECT #sql -- uncomment to see the query string
EXEC sp_executesql #sql
As the first Igor noted, the solution is dynamic SQL. You need to construct the underlying SQL statement correctly.
The following code casts all columns to varchar() and then concatenates them together. The final form of the SQL removes the last "+" sign and adds the from statement:
declare #sql varchar(max);
select #sql = (select 'cast('+coalesce(column_name, '') + ' as varchar(255)) +'
from information_schema.columns
where table_name = <whatever>
for xml path ('')
);
select #sql = left(#sql, len(#sql - 2)) + ' from t';
exec(#sql);
I admit to being US-centric and rarely using internationalization. The whole thing also works with nvarchars().
Try the below one
GO
DECLARE #ColumnsList VARCHAR(MAX), #SelectStatement VARCHAR(MAX),#TargetTable VARCHAR(250) ,#FINALSQL NVARCHAR(MAX)
SET #TARGETTABLE ='TempData'
SELECT #ColumnsList = COALESCE( #ColumnsList+' + '','' +' ,'') + 'Cast('+ A.COLUMN_NAME + ' AS Varchar(250))'
FROM (select Column_Name from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME= #TARGETTABLE) A
SELECT #FinalSql = 'Select ' +#ColumnsList + ' FROM ' + #TARGETTABLE
EXEC SP_EXECUTESQL #FINALSQL
GO