I want to select all distinct name from person table to VARCHAR variable .
I have write a query that returns all name as follow.
DECLARE #pName as VARCHAR(MAX)
SET #pName=''
SELECT #pName += RTRIM(FullName) + ','
FROM Persons
SELECT #pName
When I try to select distinct on FullName, SQL Server throws an exception.
DECLARE #pName as VARCHAR(MAX)
SET #pName=''
SELECT DISTINCT FullName, #pName += RTRIM(FullName) + ','
FROM Persons
SELECT #pName
Msg 141, Level 15, State 1, Line 3
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.
Distinct on variable name return only first Name
SELECT DISTINCT #pName += RTRIM(FullName) +
FROM Persons
SELECT #pName
How can I select distinct name to string variable from SELECT statement?
Thanks in advance
You can get the same distinct result without using the variable also.
SELECT STUFF((SELECT distinct ',' + FullName FROM Persons
FOR xml path ('')
), 1, 1, '')
Using variable - Add a group By
DECLARE #pName as VARCHAR(MAX)
set #pName=''
SELECT #pName+= RTRIM(FullName) + ',' FROM Persons Group By FullName
select #pName
DECLARE #pName as VARCHAR(MAX)
with cte as(
SELECT DISTINCT FullName FROM Persons
)
Select #pName = coalesce(#pName + ', ', '') + FullName
from cte
select #pName
Related
I want to be able to get the result of a query stored in a column, parametrized by value in another one. Model is more relational ( queries are in a 1--n linked table ), but to keep it simple :
value | query
-------------
25 | SELECT id, name FROM courses
12 | SELECT id, name FROM countries
I want to be able to get the results of the queries, so something like
SELECT EXEC(query + ' WHERE id = ' + value) FROM table
I would like to do without the application side to do that.
Is it possible ?
PS: the risk of SQL Injection does not come into play, it's already managed.
One posible approach is to generate and execute a dynamic statement for all your possible SELECT statements.
Table:
CREATE TABLE #Statements (
[value] int,
[query] nvarchar(max)
)
INSERT INTO #Statements
([value], [query])
VALUES
(25, N'SELECT id, name FROM courses'),
(12, N'SELECT id, name FROM countries')
T-SQL:
DECLARE #stm nvarchar(max) = N''
SELECT #stm = (
SELECT
CONCAT(
[query],
N' WHERE id = ',
[value],
N'; '
)
FROM #Statements
FOR XML PATH('')
)
PRINT #stm
EXEC sp_executesql #stm
Generated statements:
SELECT id, name FROM courses WHERE id = 25;
SELECT id, name FROM countries WHERE id = 12;
If you want to retrieve the results from all your statements into a single result set and if columns id and name have compatible data types, you can execute next statement (with possible CONVERT calls):
DECLARE #stm nvarchar(max) = N''
SELECT #stm = STUFF(
(
SELECT
CONCAT(
N'UNION ALL ',
[query],
N' WHERE id = ',
[value],
N' '
)
FROM #Statements
FOR XML PATH('')
),
1, 10, N'')
PRINT #stm
EXEC sp_executesql #stm
i have data in below format. this data is coming through SQL Query.
i want to show it in below format either by query or by rdlc report.
You need to use dynamic SQL to make it.
From your expected result you can try to follow thoes step to make it.
use row_number function make row number by Name, because we need to join base on that row_number.
get the use MAX and MIN to make row number calendar table. from 1 to max(rn). the table can let use outer join
declare a var #tables to make the OUTER JOIN execute SQL (each LEFT JOIN maen a group of Crew#).
declare a var #col to make column, which you want to select (Employee) from each table.
then use execute dynamic execute it.
look like this.
create table T
(
Name varchar(50),
Employee VARCHAR(50)
)
insert into T values ('Crew#1','TR123');
insert into T values ('Crew#1','311');
insert into T values ('Crew#2','DDD');
insert into T values ('Crew#2','12121');
insert into T values ('Crew#1','SDDAS');
insert into T values ('Crew#3','31114312');
insert into T values ('Crew#3','DD14124D');
insert into T values ('Crew#3','1214124121');
insert into T values ('Crew#3','SDD412AS');
DECLARE #tables AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#col AS NVARCHAR(MAX);
SET #tables = STUFF((SELECT distinct ' LEFT JOIN ' + ' (SELECT * FROM CTE WHERE Name = '''+Name+''') '+QUOTENAME(Name)+' on t1.smallRN = '+QUOTENAME(Name)+'.rn'
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = STUFF((SELECT distinct ', ' + QUOTENAME(Name)+'.Employee as '''+ QUOTENAME(Name) +''''
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = substring(#col,1, len(#col))
set #query = '
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) rn
FROM T
),CTE1 AS(
SELECT MIN(rn) smallRN,MAX(rn) bigRN
FROM CTE
UNION ALL
SELECT smallRN+1,bigRN
FROM CTE1
WHERE smallRN < bigRN
)
SELECT '+#col+'
FROM CTE1 t1 ' + #tables
execute(#query)
sqlfiddle
Creatin tbale
First we will create a temp table where we will stock the data that you have and your table
create table #table1
(
[Crew Name] varchar(500) ,
Employee varchar(500)
)
INsert into #table1
values (....)
select * from #table1
Dynamic selection
then we will create a dynamic query to get the columns that we have, that way we can add as much crews as we want,
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
this way we will get only the first row for every column
so we have to find a way to aggregate and get the other columns as well just to demonstrate i will union the Mmin also this is where i stoped my testes but you can do more then this with some testes
now the union :
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
union
select ' +#ColumnName + '
from #table1
Pivot ( MIN(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
here is the result :
if you follow this way i'm sure that you will find a way to union all the result
You can add this result into a temp table
then add a column which will be a reference into this temp table
then use pivot function
To know more about pivot Visit :
https://msdn.microsoft.com/en-us/azure/data-lake-analytics/u-sql/pivot-and-unpivot-u-sql
you can use also SSIS to a very handy tool and easy to use
Using dynamic PIVOT if you dont have a set Crew columns.
DECLARE #ColumnString VARCHAR(256)
DECLARE #ColumnHeadrer VARCHAR(256)
DECLARE #sql varchar(1000)
CREATE TABLE #ColumnValue
(
Value VARCHAR(500),
ColumnHeader VARCHAR(256)
)
INSERT INTO #ColumnValue (Value, ColumnHeader)
SELECT DISTINCT '[' + CrewName + ']',
'ISNULL(' + CrewName + ','''') AS ' + CrewName
FROM CrewTable
SELECT #ColumnString = COALESCE(#ColumnString + ',', '') + Value,
#ColumnHeadrer = COALESCE(#ColumnHeadrer + ',', '') + ColumnHeader
FROM #ColumnValue
SET #sql =
'
SELECT ' + #ColumnHeadrer + '
FROM
(
SELECT Employee,
CrewName,
ROW_NUMBER() OVER(PARTITION BY CrewName ORDER BY CrewName) AS rnk
FROM CrewTable
) AS P
PIVOT
(
MAX(Employee) FOR [CrewName] IN ('+#ColumnString+')
) AS pv
'
EXEC (#sql)
I have a dynamic single row Table like:
PersonId|FirstName|LastName|Address|PhoneNumber
-----------------------------------------------
1 Anuj Tamrakar NY +525418
I want to pivot this table and want an output in temp table like:
PersonalDetails|Value
----------------------
PersonId 1
FirstName Anuj
LastName Tamrakar
Address NY
PhoneNumber +525418
The first Table is a dynamic single row temp table. For this example, I have 5 columns. I may have more or less columns depending on my criteria
You actually want to UNPIVOT:
SELECT PersonalDetails, Value
FROM
(SELECT CAST([PersonId] AS VARCHAR(MAX)) AS [PersonId],
CAST([FirstName] AS VARCHAR(MAX)) AS [FirstName],
CAST([LastName] AS VARCHAR(MAX)) AS [LastName],
CAST([Address] AS VARCHAR(MAX)) AS [Address],
CAST([PhoneNumber] AS VARCHAR(MAX)) AS [PhoneNumber]
FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN
([PersonId], [FirstName], [LastName], [Address], [PhoneNumber])
) AS unpvt;
All 'to-be-unpivoted' fields have to be of the same type, hence the use of CAST.
Demo here
For a dynamic number of columns you have to use dynamic sql:
DECLARE #cols VARCHAR(MAX) = ''
DECLARE #cast_cols VARCHAR(MAX) = ''
DECLARE #qry VARCHAR(MAX)
SELECT #cols = #cols + ',[' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SELECT #cast_cols = #cast_cols + ',CAST([' + COLUMN_NAME + '] AS VARCHAR(MAX)) AS [' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SET #cols = STUFF(#cols, 1, 1, '')
SET #cast_cols = STUFF(#cast_cols, 1, 1, '')
SET #qry = 'SELECT PersonalDetails, Value FROM ('
+ #cast_cols +
'FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN (' + #cols + ')
) AS unpvt'
EXEC (#qry)
If you really have a single row in the original table, then you can use a series of UNION operations to get your output:
SELECT 'PersonId' AS PersonalDetails, PersonId AS Value
FROM yourTable
UNION ALL
SELECT 'FirstName' AS PersonalDetails, FirstName AS Value
FROM yourTable
UNION ALL
SELECT 'LastName' AS PersonalDetails, LastName AS Value
FROM yourTable
UNION ALL
SELECT 'Address' AS PersonalDetails, Address AS Value
FROM yourTable
UNION ALL
SELECT 'PhoneNumber' AS PersonalDetails, PhoneNumber AS Value
FROM yourTable
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.yourTableName')
This gives you your column names. You simply insert the column names in your new table and use ``, insert into temp(PersonalDetails, Value) values(column1,select column1 from SingleRowTable
I have a variable
DECLARE #CustomerName NVARCHAR(50);
I would like to take the results of the query below and concat it into the variable that I can use to return the values
SELECT Firstname, Lastname FROM CustomerData
100 Returned Records
The following query gives me the error in the subject
DECLARE #CustomerName nvarchar(50);
SELECT #CustomerName = (SELECT Firstname, Lastname FROM CustomerData)
SELECT #CustomerName AS 'Customer Name';
How do I fix this?
A scalar variable can only be bound to a single value. For example:
declare #CustomerName nvarchar(50);
select top 1 #CustomerName = Firstname + ' ' + Lastname from CustomerData;
If you have more than one row, a scalar variable probably won't do what you want.
Example SQL Fiddle
Use concat function to join the firstname and lastname as below...
-- for mysql
SELECT #CustomerName = (SELECT concat(Firstname,' ',Lastname) AS Name FROM CustomerData)
-- for sql-server
SELECT #CustomerName = (SELECT Firstname + ' ' + Lastname AS Name FROM CustomerData)
you need to have a colon before the equals to do assignment to your user defined variable
MySQL
SET #CustomerName := (SELECT GROUP_CONCAT(CONCAT(Firstname, ' ', Lastname)) FROM CustomerData);
SELECT #CustomerName AS 'Customer Name';
concat the names together because you can only assign one value to the variable
you can use SELECT INTO if you prefer it that way.
SELECT GROUP_CONCAT(CONCAT(Firstname, ' ', Lastname)) INTO #CustomerName FROM CustomerData;
T-SQL
DECLARE #CustomerName nvarchar(50);
SELECT #CustomerName = Firstname + ' ' + Lastname FROM customerdata;
SELECT #CustomerName;
this assumes you have only one name if you have more you should either add top 1 (as Lawrence did in his answer) or you can stuff it all in one string like so.
SELECT #CustomerName = (
SELECT
stuff(
(
select cast(',' as varchar(max)) + c.firstname + ' ' + c.lastname
from customerdata c
order by c.firstname
for xml path('')
), 1, 1, ''
) AS Customers
);
What is the TSQL syntax to format my output so that the column values appear as a string, seperated by commas.
Example, my table CARS has the following:
CarID CarName
----------------
1 Porsche
2 Mercedes
3 Ferrari
How do I get the car names as : Porsche, Mercedes, Ferrari
SELECT LEFT(Car, LEN(Car) - 1)
FROM (
SELECT Car + ', '
FROM Cars
FOR XML PATH ('')
) c (Car)
You can do a shortcut using coalesce to concatenate a series of strings from a record in a table, for example.
declare #aa varchar (200)
set #aa = ''
select #aa =
case when #aa = ''
then CarName
else #aa + coalesce(',' + CarName, '')
end
from Cars
print #aa
If you are running on SQL Server 2017 or Azure SQL Database you do something like this :
SELECT STRING_AGG(CarName,',') as CarNames
FROM CARS
You can do this using stuff:
SELECT Stuff(
(
SELECT ', ' + CARS.CarName
FROM CARS
FOR XML PATH('')
), 1, 2, '') AS CarNames
DECLARE #CarList nvarchar(max);
SET #CarList = N'';
SELECT #CarList+=CarName+N','
FROM dbo.CARS;
SELECT LEFT(#CarList,LEN(#CarList)-1);
Thanks are due to whoever on SO showed me the use of accumulating data during a query.
Another solution within a query :
select
Id,
STUFF(
(select (', "' + od.ProductName + '"')
from OrderDetails od (nolock)
where od.Order_Id = o.Id
order by od.ProductName
FOR XML PATH('')), 1, 2, ''
) ProductNames
from Orders o (nolock)
where o.Customer_Id = 525188
order by o.Id desc
(EDIT: thanks #user007 for the STUFF declaration)
Please try this with the following code:
DECLARE #listStr VARCHAR(MAX)
SELECT #listStr = COALESCE(#listStr+',' , '') + CarName
FROM Cars
SELECT #listStr
DECLARE #SQL AS VARCHAR(8000)
SELECT #SQL = ISNULL(#SQL+',','') + ColumnName FROM TableName
SELECT #SQL