Transform a SELECT * query to string - sql

I have a query that returns a row
SELECT *
FROM table
WHERE id = 1;
I want to save the result into a nvarchar sql variable. I have seen similar questions Convert SQL Server result set into string but they only use select with the name of the columns, never with *.
select *
from table
where id = 1
for xml path ('')
However the answer is <column1>value1</column1> <column2>value2</column2> and I just want it to be value1, value2
Is there a way to achieve this? thank you!

If open to a helper function.
This will convert virtually any row, table or query to a string (delimited or not).
In the following examples I selected a PIPE delimiter with a CRLF line terminator.
Please note the usage and placement of _RN when a line terminator is required. Also note the ,ELEMENTS XSINIL ... this will included null values as empty string. If you want to exclude null values, simply omit the ,ELEMENTS XSINIL
Example as Entire Table or dbFiddle
Declare #YourTable Table (id int,[col_1] varchar(50),[col_2] varchar(50),[col_3] varchar(50),[col_n] varchar(50)) Insert Into #YourTable Values
(1,'data1','data2','data3','data4')
,(2,'data5','data6','data7','data8')
-- Entire Table
Declare #XML xml = (Select *,_RN=Row_Number() over (Order By (Select null)) From #YourTable for XML RAW,ELEMENTS XSINIL )
Select [dbo].[svf-str-Data-To-Delimited]('|',char(13)+char(10),#XML)
Returns
1|data1|data2|data3|data4
2|data5|data6|data7|data8
Example as Row Based
Select A.ID
,AsAString = [dbo].[svf-str-Data-To-Delimited]('|',char(13)+char(10),B.XMLData)
From #YourTable A
Cross Apply ( values ( (select a.* for xml RAW,ELEMENTS XSINIL )) )B(XMLData)
Returns
ID AsAString
1 1|data1|data2|data3|data4
2 2|data5|data6|data7|data8
The Function if Interested
CREATE Function [dbo].[svf-str-Data-To-Delimited] (#Delim varchar(50),#EOL varchar(50),#XML xml)
Returns varchar(max)
Begin
Return(
Select convert(nvarchar(max),(
Select case when Item='_RN' then ''
else case when nullif(lead(Item,1) over (Order by Seq),'_RN') is not null
then concat(Value,#Delim)
else concat(Value,#EOL)
end
end
From (
Select Seq = row_number() over(order by (select null))
,Item = xAttr.value('local-name(.)', 'nvarchar(100)')
,Value = xAttr.value('.','nvarchar(max)')
From #XML.nodes('/row/*') xNode(xAttr)
) A
Order By Seq
For XML Path (''),TYPE).value('.', 'nvarchar(max)') )
)
End

You can easily store the result as an XML string:
select *
from (values (1, 'x', getdate())) v(id, a, b)
where id = 1
for xml path ('');
Or as a JSON string:
select *
from (values (1, 'x', getdate())) v(id, a, b)
where id = 1
for json auto;

If you don't mind Using dynamic SQL (and INFORMATION_SCHEMA dictionary), for example, for SQL Server this works:
DECLARE #sql nvarchar(max) = '',
#result nvarchar(max),
#id int = 1
SELECT #sql += '+'',''+convert(nvarchar,' + QUOTENAME(column_name) +')' from INFORMATION_SCHEMA.columns where table_name = 'Student'
SET #sql = 'select #result=' + stuff(#sql,1,5,'') + ' from student where id = ' + CAST(#id as nvarchar)
EXECUTE sp_executesql #sql, N'#result nvarchar(max) OUTPUT', #result=#result OUTPUT
SELECT #result as MyOutput

Related

Mask values in a SQL Query string for SQL Server

I am a SQL Server DBA. I would like to write a procedure which I can provide to rest of my team where they can view the text for currently running queries on the server (Similar to how we view in sp_who2) but with all the values masked.
Examples:
Query text
Query text after Masking
Select * from sometable where rating = '4'
Select * from sometable where rating = '****'
Select name, id from sometable where id = '3233'
Select name, id from sometable where id = '****'
UPDATE Customers SET ContactName = 'Alfred Schmidt' WHERE CustomerID = 1;
UPDATE Customers SET ContactName = '****' WHERE CustomerID = ****;
INSERT INTO Customers (CustomerName, ContactName) VALUES ('Cardinal', 'Tom B. Erichsen');
INSERT INTO Customers (CustomerName, ContactName) VALUES ('*****', '****');
If I understand correctly your issue.
You can use this query:
select
r.session_id,
r.status,
r.command,
r.cpu_time,
r.total_elapsed_time,
t.text
from sys.dm_exec_requests as r
cross apply sys.dm_exec_sql_text(r.sql_handle) as t
e.g.
I run it on my SQL server right now:
(#P1 nvarchar(5),#P2 bigint,#P3 int,#P4 numeric(28, 12),#P5 nvarchar(5),#P6 datetime,#P7 datetime)
SELECT SUM(A.SETTLEAMOUNTCUR) FROM CUSTSETTLEMENT A,CUSTTRANS B WHERE ((A.DATAAREAID=#P1) AND (((A.TRANSRECID=#P2) AND (A.CANBEREVERSED=#P3)) AND (A.SETTLEAMOUNTCUR<>#P4))) AND ((B.DATAAREAID=#P5) AND (((B.RECID=A.OFFSETRECID) AND (B.TRANSDATE>=#P6)) AND (B.TRANSDATE<=#P7)))
All variables are hidden.
You could try some XML-trickery to handle the strings.
First replace all single quotes with an empty tag <X/> to get a XML that looks like this.
INSERT INTO Customers (CustomerName, ContactName)
VALUES (<X />Cardinal<X />, <X />Tom B. Erichsen<X />);
Then you shred the xml to get the text nodes and the node numbers where mod 2 is 0 is the ones you want to mask.
After that you can rebuild your query string using the mask values.
I have not found a way to deal with numbers other then removing all numbers from the query using Translate or nested replace and that will of course also remove numbers from table names and column names as well.
You could try something like this.
declare #S nvarchar(max);
declare #X xml;
set #S = N'UPDATE Customers SET ContactName = ''Alfred Schmidt'' WHERE CustomerID = 1;';
set #X = replace(#S, '''', '<X/>');
with C as
(
select T.X.value('.', 'nvarchar(max)') as V,
row_number() over(order by T.X) as RN
from #X.nodes('text()') as T(X)
)
select #S = (
select case when C.RN % 2 = 0 then '''*****''' else C.V end
from C
order by C.RN
for xml path(''), type
).value('text()[1]', 'nvarchar(max)');
set #S = translate(#S, '0123456789', '**********')
print #S;
Result:
UPDATE Customers SET ContactName = '*****' WHERE CustomerID = *;
Note: Just realized that this solution does not handle the cases where the string values contains single quotes but I think this is something that possibly can inspire more robust solution so I will leave it here.
sys.sp_get_query_template
fiddle
declare #t nvarchar(max), #p nvarchar(max);
declare #q nvarchar(max) = 'UPDATE Customers SET ContactName = N''Alfred Schmidt'' WHERE CustomerID = 1 AND Rate = 0.75 AND Rver = 0x0102 AND DateCreated = dateadd(day, -10, ''202z0818'')';
exec sys.sp_get_query_template #querytext = #q, #templatetext = #t OUTPUT, #parameters = #p OUTPUT;
select p,
case when tp like '%int' then cast('****' as nvarchar(40))
when tp like 'decimal(%' or tp like 'numeric(%' then '**.**'
when tp like '%binary(%' then '0x****'
when tp like 'n%char%' then 'N''****'''
else '''****'''
end as rv
into #t
from
(
select *, '#'+left(s.value, charindex(' ', s.value+' ')-1) as p, stuff(s.value, 1, charindex(' ', s.value), '') as tp
from string_split(replace(#p, ',#', '#'), '#') as s
where s.value <> ''
) as ss;
update #t
set #t = replace(#t, p, rv);
select #q union all select #t;

How to Build select Query split Temp Value to two column one Per Number And Another to Text when Flag Allow 1?

I work on a query for SQL Server 2012. I have an issue: I can't build select
Query split Column Temp value to two Column When row in the temp table #nonparametric has the flag Allow = 1,
it must split column Temp value from #nonparametric to two column when the flag Allow = 1 .
suppose column Temp value has value 50.40 kg it must split to two column
First column with number so it will have 50.40 and it will be same Name as Parametric .
Second column with Text so it will have kg and it will be same Name as Parametric + 'Units'.
meaning Name will be ParametricUnit .
I need to build query that split this on two column when Flag Allow =1 .
create table #nonparametricdata
(
PART_ID nvarchar(50) ,
CompanyName nvarchar(50),
PartNumber nvarchar(50),
DKFeatureName nvarchar(100),
Tempvalue nvarchar(50),
FlagAllow bit
)
insert into #nonparametricdata
values
('1222','Honda','silicon','package','15.50Am',0),
('1900','MERCEIS','GLASS','family','90.00Am',1),--Build select query split data because FlagAllow=1
('5000','TOYOTA','alominia','source','70.20kg',0),
('8000','MACDA','motor','parametric','50.40kg',1),----Build select query split data because FlagAllow=1
('8900','JEB','mirror','noparametric','75.35kg',0)
create table #FinalTable
(
DKFeatureName nvarchar(50),
DisplayOrder int
)
insert into #FinalTable (DKFeatureName,DisplayOrder)
values
('package',3),
('family',4),
('source',5),
('parametric',2),
('noparametric',1)
what I try is below :
DECLARE #SelectqueryData NVARCHAR(MAX)
SELECT
#SelectqueryData = STUFF(
(
SELECT ', ' + case when B.FlagAllow = 1 then '['+A.DKFeatureName+'],['+A.DKFeatureName+'Unit]' else quotename(A.DKFeatureName) end
FROM #FinalTable A
join (Select distinct DKFeatureName,FlagAllow
From #nonparametricdata
) B on A.DKFeatureName=B.DKFeatureName
ORDER BY DisplayOrder
FOR XML PATH ('')
),1,2,''
)
select #SelectqueryData
--select #SelectqueryData from table
Expected Result is :
[noparametric], [parametric]--QueryGetNumber,[parametricUnit]--QueryGetUnitOfMeasure
, [package], [family]--QueryGetNumber,[familyUnit]--QueryGetUnitOfMeasure, [source]
when make query above it must give me result as image(for Explain Only) :
You're looking for a DYNAMIC PIVOT
Example
DECLARE #SelectqueryData NVARCHAR(MAX)
SELECT #SelectqueryData = STUFF( (
SELECT ', ' + case when B.FlagAllow = 1 then '['+A.DKFeatureName+'],['+A.DKFeatureName+'Unit]' else quotename(A.DKFeatureName) end
FROM #FinalTable A
join (Select distinct DKFeatureName,FlagAllow
From #nonparametricdata
) B on A.DKFeatureName=B.DKFeatureName
ORDER BY DisplayOrder
FOR XML PATH ('')
),1,2,''
)
Declare #SQL varchar(max) = '
Select *
From (
Select A.Part_ID
,A.PartNumber
,A.CompanyName
,B.*
From #nonparametricdata A
Cross Apply ( values ( DKFeatureName ,case when FlagAllow=1 then left(TempValue,patindex(''%[A-Z]%'',TempValue+''A'')-1) else TempValue end )
,( DKFeatureName+''Unit'',case when FlagAllow=1 then substring(TempValue,patindex(''%[A-Z]%'',TempValue+''A''),10) else null end )
) B(Item,Value)
) src
Pivot (max(value) for Item in ('+#SelectqueryData+') ) pvt
'
--Print #SQL
Exec(#SQL)
Returns

Different SQL Select query

I need to write SQL query in order to extract some data.
i have this data in my table:
ID Store Value
1 9921 NOK
2 9921 NOK1
3 9921 OK3
what i need is to get data from select query like this form:
9921 NOK,NOK1,OK3
Any help please ?
You can use STUFF:
SELECT DISTINCT Store,
STUFF((SELECT ',' + Value
FROM Your_Table
WHERE Store = 9921
FOR XML PATH('')), 1, 1, '')
FROM Your_Table
Try to accomplish your excepted output by using COALESCE;
Create a sample table for testing purpose
CREATE TABLE SampleData (id INT ,store INT ,value NVARCHAR(50))
INSERT INTO SampleData VALUES (1 ,9921 ,'NOK')
INSERT INTO SampleData VALUES (2 ,9921 ,'NOK1')
INSERT INTO SampleData VALUES (3 ,9921 ,'NOK2')
Create a Scalar-Valued Function
Alter FUNCTION fun_GetCombinedData
(
#store int
)
RETURNS nvarchar(max)
AS
BEGIN
-- Declare the return variable here
DECLARE #CombineValue nvarchar(max)
SELECT #CombineValue = COALESCE(#CombineValue + ', ', '') + value
FROM SampleData where store=#store
RETURN #CombineValue
END
GO
Final Query,
SELECT store
,dbo.fun_GetCombinedData(store) AS value
FROM SampleData
GROUP BY store
Expected Output:
store | value
------------------------
9921 | NOK,NOK1,NOK2
This is one of the way to simplify your select query.
Using T-SQL we can do it this way:
declare #store int = 9921, #values varchar(max) = ''
select #values = #values
+ case
when #values = '' then ''
else ','
end + value
from table_name
where store = #store
order by id
select #store, #values
Go through this below example
Demo: [SQLFiddle]
The SQL I used is as below,
SELECT
store,
STUFF(
(SELECT DISTINCT ',' + value
FROM SampleData
WHERE store = a.store
FOR XML PATH (''))
, 1, 1, '') AS CombineValues
FROM SampleData AS a
GROUP BY store
you will see your expected result as "CombineValues"
store CombineValues
9921 NOK,NOK1,NOK2

T-SQL - remove chars from string beginning from specific character

from table I retrieves values, for example,
7752652:1,7752653:2,7752654:3,7752655:4
or
7752941:1,7752942:2
i.e. string may contain any quantity of substrings.
What I need: remove all occurrences of characters from char ':' to a comma char.
For example,
7752652:1,7752653:2,7752654:3,7752655:4
should be
7752652,7752653,7752654,7752655
How do it?
Replace : with start tag <X>.
Replace , with end tag </X> and an extra comma.
Add an extra end tag to the end </X>.
That will give you a string that look like 7752941<X>1</X>,7752942<X>2</X>.
Cast to XML and use query(text()) to get the root text values.
Cast the result back to string.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table T
(
C varchar(100)
)
insert into T values
('7752652:1,7752653:2,7752654:3,7752655:4'),
('7752941:1,7752942:2')
Query 1:
select cast(cast(replace(replace(T.C, ':', '<X>'), ',', '</X>,')+'</X>' as xml).query('text()') as varchar(100)) as C
from T
Results:
| C |
|---------------------------------|
| 7752652,7752653,7752654,7752655 |
| 7752941,7752942 |
declare #query varchar(8000)
select #query= 'select '+ replace (
replace('7752652:1,7752653:2,7752654:3,7752655:4',',',' t union all select ')
,':',' t1 , ')
exec(';with cte as ( '+#query+' ) select cast(t1 as varchar)+'','' from cte for xml path('''')')
Try this:
DECLARE #Data VARCHAR(100) = '7752652:1,7752653:2,7752654:3,7752655:4'
DECLARE #Output VARCHAR(100) = ''
WHILE CHARINDEX(':', #Data) > 0
BEGIN
IF LEN(#Output) > 0 SET #Output = #Output + ','
SET #Output = #Output + LEFT(#Data, CHARINDEX(':', #Data)-1)
SET #Data = STUFF(#Data,
1,
(CASE CHARINDEX(',', #Data)
WHEN 0 THEN LEN(#Data)
ELSE CHARINDEX(',', #Data)
END) - CHARINDEX(':', #Data),
'')
END
SELECT #Output AS Result -- 7752652,7752653,7752654,7752655
Hope this will help.
I borrowed the Splitter function from here. You could use any delimiter parser you may already be using.
Parse the string to table values
Used Substring function to remove values after ':'
Use For xml to re-generate CSV
Test Data:'
IF OBJECT_ID(N'tempdb..#temp')>0
DROP TABLE #temp
CREATE TABLE #temp (id int, StringCSV VARCHAR(500))
INSERT INTO #temp VALUES ('1','7752652:1,7752653:2,7752654:3,7752655:4')
INSERT INTO #temp VALUES ('2','7752656:1,7752657:3,7752658:4')
INSERT INTO #temp VALUES ('3','7752659:1,7752660:2')
SELECT * FROM #temp t
Main Query:
;WITH cte_Remove(ID, REMOVE) AS
(
SELECT y.id AS ID,
SUBSTRING(fn.string, 1, CHARINDEX(':', fn.string) -1) AS Removed
FROM #temp AS y
CROSS APPLY dbo.fnParseStringTSQL(y.StringCSV, ',') AS fn
)
SELECT DISTINCT ID,
STUFF(
(
SELECT ',' + REMOVE
FROM cte_Remove AS t2
WHERE t2.ID = t1.ID
FOR XML PATH('')
),1,1,'') AS col2
FROM cte_Remove AS t1
Cleanup Test Data:
IF OBJECT_ID(N'tempdb..#temp') > 0
DROP TABLE #temp
I solved this problem with CLR function. It is more quickly and function can be used in complex queries
public static SqlString fnRemoveSuffics(SqlString source)
{
string pattern = #":(\d+)";
string replacement = "";
string result = Regex.Replace(source.Value, pattern, replacement);
return new SqlString(result);
}

How to make a list of T-SQL results with comma's between them?

Suppose we have a simple query like this:
SELECT x
FROM t
WHERE t.y = z
If we have one record in the result set, I want to set variable #v to that one value. If we have two or more records, I'd like the results to be separated by a comma and a space. What is the best way to write this T-SQL code?
Example:
result set of 1 record:
Value1
result set of 2 records:
Value1, Value2
result set of 3 records:
Value1, Value2, Value3
this will give you the list of values in a comma separated list
create table #temp
(
y int,
x varchar(10)
)
insert into #temp values (1, 'value 1')
insert into #temp values (1, 'value 2')
insert into #temp values (1, 'value 3')
insert into #temp values (1, 'value 4')
DECLARE #listStr varchar(255)
SELECT #listStr = COALESCE(#listStr+', ', '') + x
FROM #temp
WHERE #temp.y = 1
SELECT #listStr as List
drop table #temp
You can use XML to do that:
DECLARE #V VarChar(4000);
SELECT #V = CONVERT(VarChar(4000), (
SELECT x + ', '
FROM t
WHERE t.y = z
FOR XML PATH('')
));
-- To remove the final , in the list:
SELECT #V = LEFT(#V, LEN(#V) - 2);
SELECT #V;
For other options check out Concatenating Row Values in SQL.
Since it's SQL Server 2008, you can use FOR XML:
SELECT SUBSTRING(
(SELECT ',' + t.x
FROM t
WHERE t.y = z
FOR XML PATH('')),
2,
200000) AS CSV
FOR XML PATH('') selects the table as XML, but with a blank path.
The SUBSTRING(select, 2, 2000000) removes the leading ', '
You could use a recursive CTE for this:
CREATE TABLE #TableWithId (Id INT IDENTITY(1,1), x VARCHAR)
INSERT INTO #TableWithId
SELECT x
FROM t
WHERE t.y = z
WITH Commas(ID, Flattened)
AS
(
-- Anchor member definition
SELECT ID, x AS Flattened
FROM #TableWithId
WHERE ID = 1
UNION ALL
-- Recursive member definition
SELECT #TableWithId.Id, Flattened + ',' + x
FROM #TableWithId
INNER JOIN Commas
ON #TableWithId.Id + 1 = Commas.Id
)
-- Statement that executes the CTE
SELECT TOP 1 Flattened
FROM Commas
ORDER BY id;
GO
How about something like this???
DECLARE #x AS VARCHAR(2000)
SET #x = ''
SELECT #x = #x + RTRIM(x) + ','
FROM t
SELECT #x = SUBSTRING(#x, 1, LEN(#x) - 1)
PRINT #x