Getting a list of text concatenated in a group by - sql

Say I have this data:
site cell value
a b "1"
a c "2"
And I want the output for the format:
site value
a "b=1,c=2"
Is it possible with SQL?
PS: I am using access. But even if access does not support this particular syntax I would like to know any database that can.

Declare #tbl table ([site] nvarchar(100),Cell nvarchar(100),Value nvarchar(100))
INSERT INTO #tbl values('A','b','1')
INSERT INTO #tbl values('A','c','2')
SELECT [Site],
SUBSTRING(
(
select ' ,'+ Cell +'=' + CAST(value AS VARCHAR)
from #tbl b
WHERE a.[Site] = b.[Site]
FOR XML PATH('')
)
,3,100)
FROM #tbl a
GROUP BY a.[Site]

It is possible to do this in MySQL with GROUP_CONCAT

Related

How to remove unwanted numbers and/or Special characters from String field in SSIS or SQL

I am new to SSIS. I am trying extract the data from SharePoint and load the data into SQL Server 2012. Most of the fields are coming fine except one. I am getting the unwanted values (random number and # character) like
117;#00.010;#120;#00.013
where I want to display
00.010;00.013
I tried to use below code in Derived column but still no luck
REPLACE([Related Procedure], SUBSTRING([Related Procedure], 1, FINDSTRING([Related Procedure], "#", 1)), "")
and this is the output I am getting if I use the above code
00.010;#120;#00.013
My desired output is
00.010;00.013
Please note this is using TSQL, it is not an SSIS expression. Below is a solution that will work in SQL Server 2017 or newer. The STRING_AGG function is SQL SERVER 2017 or newer and STRING_SPLIT is SQL SERVER 2016 or newer.
I use STRING_SPLIT to break apart the string by ;, then STRING_AGG to recombine the pieces you want to keep. I added another record to my example to demonstrate how you need to GROUP BY to keep the values in separate rows, otherwise all your values would come back in a single row.
CREATE TABLE #MyTable
(
Id INT IDENTITY(1,1)
, [Related Procedure] VARCHAR(100)
)
INSERT INTO #MyTable VALUES
('117;#00.010;#120;#00.013')
, ('118;#00.011;#121;#00.014')
SELECT
STRING_AGG(REPLACE([value], '#', ''), ';')
FROM
#MyTable
CROSS APPLY STRING_SPLIT([Related Procedure], ';')
WHERE
[value] LIKE '%.%'
GROUP BY
Id
Please try this:
IF (OBJECT_ID('tempdb..#temp_table') IS NOT NULL)
BEGIN
DROP TABLE #temp_table
END;
CREATE TABLE #temp_table
(
id int identity(1,1),
String VARCHAR(MAX)
)
INSERT #temp_table SELECT '117;#00.010;#120;#00.013'
;with tmp (id, value)as (
SELECT id, replace(value, '#','')
FROM #temp_table
CROSS APPLY STRING_SPLIT(String, ';')
where value like '%.%'
)
SELECT STUFF((SELECT '; ' + value -- or CAST(value AS VARCHAR(MAX)) [text()]
from tmp
where id= t.id
for xml path(''), TYPE) .value('.','NVARCHAR(MAX)'),1,2,' ') value
FROM tmp t
or since your sql server version is 2017, you can use STRING_AGG instead of STUFF to concatenate strings returned via CTE.
SELECT STRING_AGG(value, NVARCHAR(MAX)) AS csv FROM tmp group by id;

Efficient way to merge alternating values from two columns into one column in SQL Server

I have two columns in a table. I want to merge them into a single column, but the merge should be done taking alternate characters from each columns.
For example:
Column A --> value (1,2,3)
Column B --> value (A,B,C)
Required result - (1,A,2,B,3,C)
It should be done without loops.
You need to make use of the UNION and get a little creative with how you choose to alternate. My solution ended up looking like this.
SELECT ColumnA
FROM Table
WHERE ColumnA%2=1
UNION
SELECT ColumnB
FROM TABLE
WHERE ColumnA%2=0
If you have an ID/PK column that could just as easily be used, I just didn't want to assume anything about your table.
EDIT:
If your table contains duplicates that you wish to keep, use UNION ALL instead of UNION
Try This;
SELECT [value]
FROM [Table]
UNPIVOT
(
[value] FOR [Column] IN ([Column_A], [Column_B])
) UNPVT
If you have SQL 2016 or higher you can use:
SELECT QUOTENAME(STRING_AGG (cast(a as varchar(1)) + ',' + b, ','), '()')
FROM test;
In older versions, depending on how much data you have in your tables you can also try:
SELECT QUOTENAME(STUFF(
(SELECT ',' + cast(a as varchar(1)) + ',' + b
FROM test
FOR XML PATH('')), 1, 1,''), '()')
Here you can try a sample
http://sqlfiddle.com/#!18/6c9af/5
with data as (
select *, row_number() over order by colA) as rn
from t
)
select rn,
case rn % 2 when 1 then colA else colB end as alternating
from data;
The following SQL uses undocumented aggregate concatenation technique. This is described in Inside Microsoft SQL Server 2008 T-SQL Programming on page 33.
declare #x varchar(max) = '';
declare #t table (a varchar(10), b varchar(10));
insert into #t values (1,'A'), (2,'B'),(3,'C');
select #x = #x + a + ',' + b + ','
from #t;
select '(' + LEFT(#x, LEN(#x) - 1) + ')';

Replace Quotations in records SQL Server

I have records with quotations that I would like to replace with ''.
Example:
"ASKHELLO"SE --> ASKHELLO SE
""HELLO""1 --> HELLO 1
How can I do this in SQL Server?
I know replace function, but how do I get the pattern to check for to be any character other than "".
UPDATE
wordname
SET
wordname = REPLACE(deal, '"'+ '%', '')
This is incorrect. Help, please.
I am adding another answer based on your comment about double spaces on my original answer. ID in this case is arbitrary but I am huge fan of always having a primary key of some kind. XML we meet again!
--Setup the Table
DECLARE #T TABLE (wordname VARCHAR(25))
INSERT INTO #T VALUES ('"ASKHELLO"SE'),('""HELLO""1')
SELECT * FROM #T
--DECLARE AND SET XML REPLACING " with spaces
DECLARE #XML XML =
(
SELECT ROW_NUMBER() OVER (ORDER BY wordname ASC) AS "#ID",
CONVERT(XML,'<PART>' + REPLACE(CAST(CAST(REPLACE(wordname, '"',' ') AS VARCHAR(25)) AS VARCHAR(max)),' ',' </PART><PART>') + '</PART>') AS Word
FROM #T AS T
FOR XML PATH('Node'), ROOT('Nodes'), ELEMENTS, TYPE
)
SELECT #XML
--SHRED THE XML (WHICH WILL REMOVE NULLS) AND TRIM
;WITH
SHRED AS
(
SELECT ID = FieldAlias.value('(#ID)[1]','INT'),
WordName = FieldAlias.value('(Word)[1]','varchar(max)')
FROM #XML.nodes('/Nodes/Node') AS TableAlias(FieldAlias)
)
SELECT S.ID,
LTRIM(RTRIM(S.WordName)) AS WordName
FROM Shred AS S
And it should be relatively trivial for you to update off the shredded result set at this point, but let me know if you need that too. Replace the #T with your original table to pull off your data set.
REPLACE function does a global replace within a string. So u can do simple
UPDATE
wordname
SET
deal = REPLACE(deal, '"', '')
Assuming that "wordname" is your table and "deal" is a field you're replacing.
This will simple remove the double quotes. If you need to replace it with space use ' ' instead of ''
Does this help you? Try using LTRIM to strip off leading spaces after the replace. Here's a quick example based on your code:
DECLARE #T TABLE (wordname VARCHAR(25))
INSERT INTO #T VALUES ('"ASKHELLO"SE'),('""HELLO""1')
SELECT * FROM #T
SELECT LTRIM(REPLACE(wordname, '"',' '))
FROM #T

Splitting a variable length column in SQL server safely

I have a column (varchar400) in the following form in an SQL table :
Info
UserID=1123456,ItemID=6685642
The column is created via our point of sale application, and so I cannot do the normal thing of simply splitting it into two columns as this would cause an obscene amount of work. My problem is that this column is used to store attributes of products in our database, and so while I am only concerned with UserID and ItemID, there may be superfluous information stored here, for example :
Info
IrrelevantID=666,UserID=123124,AnotherIrrelevantID=1232342,ItemID=1213124.
What I want to retrieve is simply two columns, with no error given if neither of these attributes exists in the Info column. :
UserID ItemID
123124 1213124
Would it be possible to do this effectively, with error checking, given that the length of the IDs are all variable, but all of the attributes are comma-separated and follow a uniform style (i.e "UserID=number").
Can anyone tell me the best way of dealing with my problem ?
Thanks a lot.
Try this
declare #infotable table (info varchar(4000))
insert into #infotable
select 'IrrelevantID=666,UserID=123124,AnotherIrrelevantID=1232342,ItemID=1213124.'
union all
select 'UserID=1123456,ItemID=6685642'
-- convert info column to xml type
; with cte as
(
select cast('<info ' + REPLACE(REPLACE(REPLACE(info,',', '" '),'=','="'),'.','') + '" />' as XML) info,
ROW_NUMBER() over (order by info) id
from #infotable
)
select userId, ItemId from
(
select T.N.value('local-name(.)', 'varchar(max)') as Name,
T.N.value('.', 'varchar(max)') as Value, id
from cte cross apply info.nodes('//#*') as T(N)
) v
pivot (max(value) for Name in ([UserID], [ItemId])) p
SQL DEMO
You can try this split function: http://www.sommarskog.se/arrays-in-sql-2005.html
Assuming ItemID=1213124. is terminated with a dot.
Declare #t Table (a varchar(400))
insert into #t values ('IrrelevantID=666,UserID=123124,AnotherIrrelevantID=1232342,ItemID=1213124.')
insert into #t values ('IrrelevantID=333,UserID=222222,AnotherIrrelevantID=0,ItemID=111.')
Select
STUFF(
Stuff(a,1,CHARINDEX(',UserID=',a) + Len(',UserID=')-1 ,'' )
,CharIndex
(',',
Stuff(a,1,CHARINDEX(',UserID=',a) + Len(',UserID=')-1 ,'' )
)
,400,'') as UserID
,
STUFF(
Stuff(a,1,CHARINDEX(',ItemID=',a) + Len(',ItemID=')-1 ,'' )
,CharIndex
('.',
Stuff(a,1,CHARINDEX(',ItemID=',a) + Len(',ItemID=')-1,'' )
)
,400,'') as ItemID
from #t

SQL Server query with multiple values in one column relating to another column

Situation: This table holds the relation information between a Documents table and an Users table. Certain Users need to review or approve documents (Type). I would like to have it to where I could get all of the reviewers on one line if needed. So if three users review Document 1, then a row would have 346, 394, 519 as the value, since those are the reviewers
Table: xDocumentsUsers
DocID..UserID....Type...
1........386......approver
1........346......reviewer
1........394......reviewer..
1........519......reviewer..
4........408......reviewer..
5........408......reviewer..
6........408......reviewer..
7........386......approver..
7........111......readdone..
7........346......reviewer..
8........386......approver..
8........346......reviewer..
9........386......approver..
9........346......reviewer..
10.......386......approver..
11.......386......approver..
11......346......reviewer..
12......386......approver..
12......346......reviewer..
13......386......approver..
13......346......reviewer..
14......386......approver..
14......346......reviewer..
15......386......approver
So desired result would be...
DocID..UserID................Type...
1........386....................approver
1........346,394,519......reviewer.
4........408....................reviewer..
5........408....................reviewer..
6........408....................reviewer..
7........386....................approver..
7........111....................readdone..
7........346....................reviewer..
8........386....................approver..
8........346....................reviewer..
9........386....................approver..
9........346....................reviewer..
10......386....................approver..
11......386....................approver..
11......346....................reviewer..
12......386....................approver..
12......346....................reviewer..
13......386....................approver..
13......346....................reviewer..
14......386....................approver..
14......346....................reviewer..
15......386....................approver
The FOR XML PATH is a great solution. You need to be aware, though, that it will convert any special characters in the inner SELECTs result set into their xml equivalent - i.e., & will become & in the XML result set. You can easily revert back to the original character by using the REPLACE function around the inner result set. To borrow from astander's previous example, it would look like (note that the SELECT as the 1st argument to the REPLACE function is enclosed in ():
--Concat
SELECT t.ID,
REPLACE((SELECT tIn.Val + ','
FROM #Table tIn
WHERE tIn.ID = t.ID
FOR XML PATH('')), '&', '&'))
FROM #Table t
GROUP BY t.ID
Have a look at
Emulating MySQL’s GROUP_CONCAT() Function in SQL Server 2005
Is there a way to create a SQL Server function to “join” multiple rows from a subquery into a single delimited field?
A simple example is
DECLARE #Table TABLE(
ID INT,
Val VARCHAR(50)
)
INSERT INTO #Table (ID,Val) SELECT 1, 'A'
INSERT INTO #Table (ID,Val) SELECT 1, 'B'
INSERT INTO #Table (ID,Val) SELECT 1, 'C'
INSERT INTO #Table (ID,Val) SELECT 2, 'B'
INSERT INTO #Table (ID,Val) SELECT 2, 'C'
--Concat
SELECT t.ID,
(
SELECT tIn.Val + ','
FROM #Table tIn
WHERE tIn.ID = t.ID
FOR XML PATH('')
)
FROM #Table t
GROUP BY t.ID
Does this help?
SELECT DocID
, [Type]
, (SELECT CAST(UserID + ', ' AS VARCHAR(MAX))
FROM [xDocumentsUsers]
WHERE (UserID = x1.UserID)
FOR XML PATH ('')
) AS [UserIDs]
FROM [xDocumentsUsers] AS x1