Use subquery after AS alias - sql

I am trying to use subquery after alias AS in SQL server 2019, here is my sql query:
select concat(sum(labst),' kg') as (select distinct name1 from mb52 where werks='1202') from mb52 where werks='1202';
but this query giving this error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '('.
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'from'.
I want to get the result like this:
1202
--------------------------------------------
343979.535 kg
instead of using select concat(sum(labst),' kg') as "1202",
because I get the value of werks from a variable $werks and my final SQL query look like this:
select concat(sum(labst),' kg') as (select distinct name1 from mb52 where werks in ($werks)) from mb52 where werks in ($werks);
Can anyone help me on this problem,please?

You can use dynamic sql like this
declare #sql varchar(1000)
declare #name varchar(100)
declare #werks varchar(1000) = '1202, 1200'
select distinct
#name = name1
from mb52
where werks = 1202
set #sql = 'select concat(sum(labst), '' kg'') as ''' + #name + ''' from mb52 where werks in (' + #werks + ')'
exec (#sql)
See this DBFiddle where you can try it yourself
However, there is a major problem with your query, as you write
as (select distinct name1 from mb52 where werks in ($werks))
This can return more than one value for name1 if there are more then one value in $werks
So I changed it to = 1202 like the other answer also did
Your query probably needs to more like this
set #sql2 = 'select concat(sum(labst), '' kg'') as ''' + #name + ''' from mb52 where werks = 1202'
where again I changed the in $werks into = 1202 because I think it will produce wrong results, but that is up to you.
Look at the dbfiddle and play with it until it does what you need.
EDIT
As requested in the comments, here is how the query looks like with just one value in $werks
set #sql2 = 'select concat(sum(labst), '' kg'') as ''' + #name + ''' from mb52 where werks = ' + #werks
The DBFiddle is also altered

you should use dynamic sql to get this working
DECLARE #S NVARCHAR(MAX)
SELECT distinct #S = 'select concat(sum(labst),'' kg'') as '+ name1 +' from mb52 where werks=''1202''' from mb52 where werks='1202'
EXEC (#S)

To do this, you need to use a dynamic query
like this:
DECLARE #query NVARCHAR(MAX) = 'select concat(sum(t1.labst),'' kg'') as '+ (SELECT DISTINCT
t1.name1 FROM dbo.mb52 t1 WHERE t1.werks = '1202') + ' from dbo.mb52 t1 where t1.werks=''1202'''
EXEC sp_executesql #query

Related

Get header as the first row in dynamic SQL

My table:
id name city
--------------------
1 Jim NewYork
2 Rose London
3 Kitty Seattle
......
The output:
id name city
--------------------
id name city
1 Jim NewYork
2 Rose London
3 Kitty Seattle
I can easily do it in static SQL like this, but how to do it in dynamic SQL?
Declare #sql as varchar(max)='select *';
set #sql =#sql+' from mytable';
exec(#sql)
I am not sure why you want to do that as your id looks int to me. If you want one extra string type value to the column to appear on the top, in that case you have to convert all the int to string.
Still if you want to do that you can write your query like following.
SELECT *
FROM (
SELECT cast(id AS VARCHAR(10)) AS id
,Name
,city
FROM mytable
UNION ALL
SELECT 'id'
,'name'
,'city'
) t
ORDER BY CASE
WHEN t.id = 'id'
THEN 0
ELSE 1
END
Same query can be written as dynamic query like following.
DECLARE #sql AS VARCHAR(max) = 'select * from (
select cast(id as varchar(10)) as id,Name,city';
SET #sql = #sql + ' from mytable union select ''id'',''name'', ''city'')t
order by case when t.id=''id'' then 0 else 1 end';
EXEC (#sql)
I don't know if I am overdoing this. But if you want a pure dynamic way, you can try something like
declare #sql varchar(max),
#colnameHeads varchar(max),
#colnames varchar(max);
-- building the row with column headers
set #colnameHeads = STUFF((
SELECT ',''' + COLUMN_NAME + ''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'<your-table>'
FOR XML PATH('')
), 1, 1, '')
-- casting all the values to varchar to match with header row
set #colnames = STUFF((
SELECT ',' + CONCAT('CAST(', COLUMN_NAME, ' AS VARCHAR(100))')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'<your-table>'
FOR XML PATH('')
), 1, 1, '')
-- dynamic script
set #sql = 'select '+ #colnameHeads + ' union all select '+ #colnames + ' from <your-table>';
EXEC (#sql)

Incorrect syntax near '%'. inside dynamic SQL

I just found out about dynamic SQL but when I add a wildcard like '%', I get this error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '%'.
Here is the query:
declare #Filter varchar(50)
set #Filter = '2%'
exec ('select * from dbo.tbl_coa where acct_code like ' + #Filter)
Anyway to fix this or is it impossible with dynamic SQL?
You need to enclose #Filter in quotes:
exec ('select * from dbo.tbl_coa where acct_code like ''' + #Filter + '''')
Demo on SQLFiddle
Note it is better to put the needed quotes into the query that you execute so that if you do something like
set #Filter = (SELECT ... )
The query will still work without having to do something like
set #Filter = concat('''', (select '2%'), '''')
You are concating the string incorrectly.
You should fix it to set #Filter = '''2%''', check the result below.
Demo on db<>fiddle
declare #Filter varchar(50)
set #Filter = '''2%'''
print ('select * from dbo.tbl_coa where acct_code like ' + #Filter)
// Output: select * from dbo.tbl_coa where acct_code like '2%'
Full Demo on db<>fiddle
create table tbl_coa(
acct_code varchar(10)
)
insert into tbl_coa
values('21'),('20'),('30')
declare #Filter varchar(50)
set #Filter = '''2%'''
exec ('select * from dbo.tbl_coa where acct_code like ' + #Filter)
Output
acct_code
21
20

how to use "select * into" in sp_msforeachtable -T-SQL

I have below query to create duplicate table :
select * into person1 from person
but know I need a query to create duplicate for each table in selected database.
To to this I tried like below:
Declare #Time nvarchar(10)=1
Declare #Comment nvarchar(max)
set #Comment ='select * into ?'+#Time + ' '+'from ?'
exec sp_msforeachtable #Comment
but it returns the error :
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '1'.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '1'.
Is there a way to do this ?
Following our conversation in the comments I think you will have to use dynamic sql.
You can use something like this instead:
DECLARE #Sql nvarchar(max) = '';
SELECT #Sql = #Sql + 'SELECT * INTO '+ TABLE_NAME +'1 FROM '+ TABLE_NAME +';'
FROM INFORMATION_SCHEMA.TABLES
EXEC(#SQL)
update
The above code has some drawbacks.
First, it will fail if there is a table name that doesn't follow the identifier naming rules.
Second, it will also create tables from views.
Here's a better version, that fix these issues:
DECLARE #Sql nvarchar(max);
SET #Sql = STUFF(
(
SELECT ';SELECT * INTO '+ QUOTENAME(Table_Name + '1') +' FROM '+ QUOTENAME(Table_Name)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
FOR XML PATH('')
), 1, 1, '')
EXEC (#Sql)
Another improvement here is in the way the string gets aggregated - the first version is a RBAR approach, the second one isn't (at least, to the best of my knowledge).

Execute a query returned from a scalar function

I have a scalar function that returns a query. The scalar function must return the query itself and not its' results, since it uses dynamic SQL and the variables are used as column names and table names.
So, I have something like this:
SELECT t.id,
dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom) QueryToExecute
FROM Table t
Which returns
| ID | QueryToExecute
| 1 | SELECT ColumnName1 FROM Table1 WHERE id = 1
| 2 | SELECT ColumnName2 FROM Table2 WHERE id = 2
While "QueryToExecute" returns a single value.
I want to do something like:
SELECT t.id,
EXEC(dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom)) ExecutedQuery
FROM Table t
So the result set will be:
| ID | ExecutedQuery
| 1 | Jacob
| 2 | Sarah
How can I do that?
I already have a stored procedure that gets the job done when I need to run individually, but I wanted to have the same thing on a scalar function in order to be able to embed the sub-results in more complex queries.
Thanks!
You need to use dynamic SQL:
DECALRE #sql nvarchar(max)
SELECT #sql = COALESCE(#sql,'') +
REPLACE(
dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom),
'SELECT ',
'SELECT '+ CAST(t.ID as nvarchar(max) +' as ID, '
) +' UNION ALL '
FROM Table t
SELECT #sql = LEFT(#sql,LEN(#sql)-LEN('UNION ALL '))
EXEC sp_executesql #sql
This will get all query's in one batch and execute it
You need to take your dynamic sql one step deeper, and include the id number.
This script will generate a select statement for each row, and union them all together. You then run this whole select in one go to get your output.
--set up a string variable to store your query
declare #tsql nvarchar(max);
set #tsql = '';
-- populate it with the string statements
select #tsql = #tsql + 'select ' + cast(t.id as nvarchar(10)) + ' as id , (' + dbo.queryToExecute(t.id, t.ColumnToFetch, t.TableToFetchFrom) + ') QueryToExecute union ' from Table t
--chop off the final "union"
select #tsql = left (#tsql,len(#tsql)-7);
--and run
EXEC sp_executesql #tsql

SQL results to string with wildcard

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