query not retrieving values returned from split string - sql

I generate comma seperated string and add single quite to each numbers
Here is how i do it
DECLARE #IDs NVARCHAR(max)
SELECT #IDs = COALESCE(#IDs +',', '') + ''''
+ Cast([mynos] AS NVARCHAR(255)) + ''''
FROM mytable
WHERE id = 22
If i print variable #IDs then i get below output
'78888','3333','1222'
When i use same variable in this query then query doesnt return any value
SELECT *
FROM table1
WHERE ids IN ( #IDs )
How to fix this?

It doesn't work as your query is effectively doing this:
SELECT *
FROM TABLE
WHERE Ids IN ('''78888'',''3333',''1222''');
Which would also be equivalent to:
SELECT *
FROM TABLE
WHERE Ids = '''78888'',''3333',''1222''';
If you want to do the query as you have done, you'll need to split your delomited data out again. As you're using SQL Server 2012, you can't make use of STRING_SPLIT, so you'll need to a different one; such as Jeff Moden's DelimitedSplit8K. Then you can do:
SELECT *
FROM TABLE
WHERE IDs IN (SELECT items
FROM dbo.DelimitedSplit8K (#IDs,','));
However, why are you not simply doing...
SELECT *
FROM TABLE T
WHERE EXISTS (SELECT 1
FROM myTable mT
WHERE mT.Id = 22
AND mT.myNos = T.Ids);

You can use dynamic query #id is string variable not multi-value argument
DECLARE #IDs nVARCHAR(MAX)
SELECT #IDs = COALESCE(#IDs +',' ,'') + '''' + CAST([myNos] AS nVARCHAR(255)) + ''''
FROM myTable WHERE Id = 22
DECLARE #query nVARCHAR(MAX)
SET #query = "Select * from table1 where Ids in ("+#IDs+")"
EXECUTE sp_executesql #query

I tried below and it worked
select * from table1 where id in (select mynos from mytable where id = 22)
Thanks to #Larnu for giving me idea

Related

How to put a comma separated value from a column in a table into SQL IN operator?

I have a table which has a column in which I am storing a comma separated text with single quotes for each of the comma separated values. These values are employee IDs. This is how it looks
Now, I have a SQL query wherein I need to put the value from this column into a SQL IN operator. Something like this:
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN (select CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID'
)
But this, does not work, the query when executed returns 0 rows whereas if I execute the query normally like below, it works.
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN('9F3DD4B791554DDE','C9B90D62851D43AB','828CB9E6204B4DDC')
Please suggest what I should do here. I have tried using substring to remove the first and the last character as well assuming that single quotes might be the issue, but that does not work either.
select * from EMPLOYEE_MASTER where EMPLOYEEID IN(select EMPLOYEEID from ADL_CONFIG_MAST_T where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID')
column should be same in where COLUMNNAME IN (select COLUMNNMAE from tablename)
You can create a temp varible and then use exec command to get the desired result.
declare #temp varchar(200)
select #temp=CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID'
exec('select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN (' + #temp + ')')
Try This:
DECLARE #ID VARCHAR(500);
DECLARE #Number VARCHAR(500);
DECLARE #comma CHAR;
SET #comma = ','
SET #ID = (select CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like %ATT_BIOMETRIC_OU_ID% + #comma);
Create table #temp (EMPLOYEEID varchar(500))
WHILE CHARINDEX(#comma, #ID) > 0
BEGIN
SET #Number = SUBSTRING(#ID, 0, CHARINDEX(#comma, #ID))
SET #ID = SUBSTRING(#ID, CHARINDEX(#comma, #ID) + 1, LEN(#ID))
Insert into #temp
select #Number
END
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN(select EMPLOYEEID from #temp)
The reason you are not getting it in your query is because your inner query returns only one row. So your query searches for '9F3DD4B791554DDE','C9B90D62851D43AB','828CB9E6204B4DDC' as as single record.
If your compatibility level is greater than or equal to 130 you can use STRING_SPLIT() function. Then your query would be
SELECT *
FROM EMPLOYEE_MASTER
WHERE EMPLOYEEID IN
(SELECT value AS empid
FROM ADL_CONFIG_MAST_T CROSS APPLY string_split(CM_CONFIG_VALUE, ',' )
WHERE CM_CONFIG_KEY LIKE 'ATT_BIOMETRIC_OU_ID' )
What this actually does is, it splits the CM_CONFIG_VALUE with ',' and returns them as rows. This is the value column I have referred. Then you use them with the IN clause.
Hope this helps!
Direct IN condition will not work here. You have split your string before searching. You can do that with XML options in SQL SERVER 2014
SELECT *
FROM EMP
WHERE EMPID IN (
SELECT a.c.value('.', 'VARCHAR(1000)')
FROM (
SELECT x = CAST('<a>' +
REPLACE(REPLACE(CM_CONFIG_VALUE , ',', '</a><a>'),'''','') + '</a>' AS XML )
FROM ADL_CONFIG_MAST_T
-- WHERE <your_condition>
) m
CROSS APPLY x.nodes('/a') a(c))
CHECK DEMO HERE
For the version 2016 and above you can use STRING_SPLIT with Compatibility level 130

Can you MAX(*) in SQL Server?

I am dealing with a huge list of columns (around 50) where i only need to group by one column. Is there anyway in SQL Server i can aggregate the columns by something such as
SELECT MAX(*)
FROM View1
GROUP BY Column1
instead of having to go through each one and specify an aggregate function. I have had a look online but cant find anything. Is there any advice or guidance someone can give me or is it just a case of going through each row?
Thanks
You can build query you need using system tables:
DECLARE #ViewName sysname = N'View1',
#query nvarchar(max),
#Column sysname = 'Column1'
SET #query = N'SELECT ' + #Column + ',' + CHAR(10)
SELECT #query = #query + N'MAX('+c.[name]+') as '+c.[name]+',' + CHAR(10)
FROM sys.views v
INNER JOIN sys.columns c
ON v.[object_id] = c.[object_id]
WHERE v.[name] = #ViewName AND c.[name] != #Column
SET #query = STUFF(#query,LEN(#query)-1,1,'') + 'FROM '+#ViewName + CHAR(10) + 'GROUP BY ' + #Column
PRINT #query
Output will be:
SELECT Column1,
MAX(Column2) as Column2,
MAX(Column3) as Column3,
...
MAX(ColumnN) as ColumnN
FROM View1
GROUP BY Column1
You can Ctrl+C Ctrl+V on new query window and execute, or execute it right here with:
EXEC (#query)
In case of tables - you need to use sys.tables
In case if view or table is not in default schema - you need to specify it manually.
SET #query = STUFF(#query,LEN(#query)-1,1,'') + 'FROM dbo.'+#ViewName + CHAR(10) + 'GROUP BY ' + #Column
No. Unfortunately, you're going to have to write out the columns.
If you need max value from different columns you can try as below
Select max(yourcolumn) from
(
Select col1 from yourtable
union all Select col2 from yourtable
union all Select col3 from yourtable
...
) a
No, you can not use max(*).
You will have to give a column name in max function like below
select max(column_name) from table_name;
You cannot write select max(*). This results in the error Incorrect syntax near '*'. Instead, you will need to specify the columns.
One way to get the maximum of multiple columns is to unpivot the table. An efficient way to do this is to use cross apply to generate separate row values for each column.
For example, the code below finds the maximum value across 3 different columns in all of the rows:
declare #test table
(
id int primary key clustered,
value1 int,
value2 int,
value3 int
)
insert into #test (id, value1, value2, value3)
values (1, 100, 0, 0), (2, 0, 50, 0), (3, 0, 0, 25)
select max(TestValue) -- returns 100
from #test
cross apply
(
values(value1),(value2), (value3)
) TestValues (TestValue)

Using the result of a CTE to query from table without cursor

I need to query from a table which is a result of a CTE query e.g.
;WITH CTE
AS
(
SELECT TableName
FROM dbo.TableContainingListOfTableNames
)
SELECT * FROM CTE
This will return me the names of the tables which I need to query data from.
Can I use the CTE to query from the respective tables e.g. SELECT * FROM dbo.[1006UN]? I know I could use a temp table to store these values and use a cursor to iterate with dynamic sql but I do not want to use a cursor, if at all possible.
I have tried something as simple as:
SELECT * FROM dbo.[CTE]
Which gives me the error:
Invalid object name 'dbo.CTE'.
And have went further to attempt to use dynamic SQL with the CTE:
DECLARE #query1 VARCHAR(MAX)
SELECT #query1 = N';WITH CTE
AS
(
SELECT TableName
FROM dbo.TableContainingListOfTableNames
)
SELECT * FROM dbo.["' + CTE + '"] '
EXECUTE(#query1)
Which gives me the error:
Invalid column name 'CTE'.
So firstly, is it possible to achieve this? And if not, are there any alternatives which can achieve this (avoiding cursors)?
Can be done. It's irrelevant if you use CTE or not. Once you have your tables names you can create and concatenate dynamic SELECT statements.
DECLARE #query NVARCHAR(MAX) = '';
WITH CTE AS
(
SELECT TableName
FROM dbo.TableContainingListOfTableNames
)
SELECT #query = #query + 'SELECT * FROM ' + QUOTENAME(TableName) + '; '
FROM CTE;
PRINT #query; --run print first to check
EXEC (#query);

TSQL: How to add automatically select columns

I have a problem and can't solve it. Furthermore I can't find an answer anywhere in the internet.
Simplified I have a big table with coloumns, where values to products with an ID are stored by year:
year
id
value
In my stored procedure the attributes for getting information are:
#year
#id
If you want to get information about more than one product, you can use a comma-seperated list of product-ids like ('654654,543543,987987').
My TSQL should be like this:
select year,
sum(case when id = #id[1] then value),
sum(case when id = #id[2] then value),
[...]
from table myTable
where year = #year
group by year
order by year
What I want to do is iterate throught the comma-seperated ids and for each id, I want to add a new select attribut like this (sum(case when id = #id[x] then value).
Can you help me with this problems? Any suggestions to solve it?!
Thanks for your help!
PIVOT operation could simplify the query.
But, anyway, it seems that the only way to construct such a query is to use dynamic SQL.
DECLARE
#Ids NVARCHAR(MAX),
#stmt NVARCHAR(MAX)
SET #Ids = '1,2'
-- Transform Ids into the format PIVOT understands - with square brackets.
-- Primitive way, to not overcomplicate sample.
SET #Ids = '[' + REPLACE(#Ids, ',', '], [') + ']'
PRINT #Ids -- [1], [2]
SET #Stmt = '
SELECT *
FROM Products as p
PIVOT
(
SUM(p.Value)
FOR p.Id IN (' + #Ids + ')
) AS t
ORDER BY Year'
EXEC sp_executesql #Stmt
If you need more accurate way of splitting a comma separated list into an array (table), please see this article for details.
This example is available on SQL Fiddle
As you are using stored procedure, you can use sp_executesql to executed dynimically build SQL statement.
So, you have to iterate over the CSV like this:
DECLARE #List NVARCHAR(MAX) = N'1001,dada,1002,1003'
DECLARE #ProductsID TABLE ( [ID] BIGINT )
DECLARE #XML xml = N'<r><![CDATA[' + REPLACE(#List, ',', ']]></r><r><![CDATA[') + ']]></r>'
INSERT INTO #ProductsID ([ID])
SELECT DISTINCT CAST(Tbl.Col.value('.', 'float') AS bigint)
FROM #xml.nodes('//r') Tbl(Col)
WHERE ISNUMERIC(Tbl.Col.value('.', 'varchar(max)')) = 1
SELECT [ID] FROM #ProductsID
Then, having a table with the ID to dynamically build you SQL statement and execute it.

How to return multiple values in one column (T-SQL)?

I have a table UserAliases (UserId, Alias) with multiple aliases per user. I need to query it and return all aliases for a given user, the trick is to return them all in one column.
Example:
UserId/Alias
1/MrX
1/MrY
1/MrA
2/Abc
2/Xyz
I want the query result in the following format:
UserId/Alias
1/ MrX, MrY, MrA
2/ Abc, Xyz
Thank you.
I'm using SQL Server 2005.
p.s. actual T-SQL query would be appreciated :)
You can use a function with COALESCE.
CREATE FUNCTION [dbo].[GetAliasesById]
(
#userID int
)
RETURNS varchar(max)
AS
BEGIN
declare #output varchar(max)
select #output = COALESCE(#output + ', ', '') + alias
from UserAliases
where userid = #userID
return #output
END
GO
SELECT UserID, dbo.GetAliasesByID(UserID)
FROM UserAliases
GROUP BY UserID
GO
Well... I see that an answer was already accepted... but I think you should see another solutions anyway:
/* EXAMPLE */
DECLARE #UserAliases TABLE(UserId INT , Alias VARCHAR(10))
INSERT INTO #UserAliases (UserId,Alias) SELECT 1,'MrX'
UNION ALL SELECT 1,'MrY' UNION ALL SELECT 1,'MrA'
UNION ALL SELECT 2,'Abc' UNION ALL SELECT 2,'Xyz'
/* QUERY */
;WITH tmp AS ( SELECT DISTINCT UserId FROM #UserAliases )
SELECT
LEFT(tmp.UserId, 10) +
'/ ' +
STUFF(
( SELECT ', '+Alias
FROM #UserAliases
WHERE UserId = tmp.UserId
FOR XML PATH('')
)
, 1, 2, ''
) AS [UserId/Alias]
FROM tmp
/* -- OUTPUT
UserId/Alias
1/ MrX, MrY, MrA
2/ Abc, Xyz
*/
DECLARE #Str varchar(500)
SELECT #Str=COALESCE(#Str,'') + CAST(ID as varchar(10)) + ','
FROM dbo.fcUser
SELECT #Str
group_concat() sounds like what you're looking for.
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
since you're on mssql, i just googled "group_concat mssql" and found a bunch of hits to recreate group_concat functionality. here's one of the hits i found:
http://www.stevenmapes.com/index.php?/archives/23-Recreating-MySQL-GROUP_CONCAT-In-MSSQL-Cross-Tab-Query.html
You can either loop through the rows with a cursor and append to a field in a temp table, or you could use the COALESCE function to concatenate the fields.
Sorry, read the question wrong the first time. You can do something like this:
declare #result varchar(max)
--must "initialize" result for this to work
select #result = ''
select #result = #result + alias
FROM aliases
WHERE username='Bob'