how to select distinct and concatenate in sql - sql

Lets say we have a following table with two columns and following rows of data in SQLServer-2005:
Tiger 50
Wolf 4
Tiger 53
Lion 55
Elephant 54
Rhino 52
Lion 5
Can we have a sql query that result as following: Tiger,Wolf,Lion,Elephant,Rhino as a single string varchar output?Is it possible ?
using T-SQL not possible singe I am using the result in c# as a result of executescalar
Thank you in advance.

You can use for xml path to concatenate the values:
select distinct name + ', ' as [text()]
from #t
for xml path('')
-->
Elephant, Lion, Rhino, Tiger, Wolf,
Chop of the last 2 bytes if you don't like trailing ,'s.
Not sure why you can't use T-SQL, you can use this in combination with ExecuteScalar() just fine.
Sample data:
declare #t table (name varchar(max), id int)
insert into #t
select 'Tiger', 50
union all select 'Wolf', 4
union all select 'Tiger', 53
union all select 'Lion', 55
union all select 'Elephant', 54
union all select 'Rhino', 52
union all select 'Lion', 5

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

Use GROUP_CONCAT() with DISTINCT:
SELECT GROUP_CONCAT(DISTINCT colName) FROM tblName;

Assuming you are getting this from ExecuteScalar and using the resulting composite string in C#, then you are going to end up writing a sproc, or just having your code work with the datatable.
Can you provide more detail on why you can't use a sproc? A few good examples have been provided that would do fine with that, and you can still get your scalar result

The most efficient way is probably to use a User-Defined Aggregate, but you can also abuse the UPDATE statement:
DECLARE #Result varchar(500)
SET #Result = ''
UPDATE Animals
SET #Result = #Result + Name + ','
SELECT #Result

This is how Andomar's Answer was implemented.Thanks to Andomar's answer got to learn some thing new with this .
select distinct summaryColumn + ', '
as [text()] from tablename for
xml path('')

Related

Remove Punctuation in a field in Oracle SQL Developer

I have a field in table in Oracle SQL developer that I need to remove all punctuations in a specific field. The table name is "punctuationtest"
and the function that I tried does not work, I got error with the #InputString
Here is the function that I tried : any ideas and suggestions will be helpful thanks
CREATE FUNCTION dbo.fn_RemovePunctuation
(
#InputString VARCHAR(500)
)
RETURNS VARCHAR(500)
AS
BEGIN
SELECT
#InputString = REPLACE(#InputString, P.Symbol, '')
FROM
Punctuationtest P
RETURN #InputString
END
GO
"Oracle SQL Developer" is a tool you use to establish connection to a database and do something. Which database is it? Usually, it is Oracle. But, then again, code you posted certainly is NOT Oracle - hence error you got (at least, I think so).
If your database really is Oracle, then you could try with such a regular expression (see line #6):
SQL> with test (col) as
2 (select 'abc,!23' from dual union all
3 select '?xyz,.' from dual
4 )
5 select col,
6 regexp_replace(col, '[[:punct:]]') result
7 from test;
COL RESULT
------- ----------------------------
abc,!23 abc23
?xyz,. xyz
SQL>
Or, as you want to update a table, you'd
update your_table set
that_column = regexp_replace(that_column, '[[:punct:]]');

How do I get the just the number from a SQL table where it is stored like this <PersonNumber>013870</PersonNumber>

I have a table that stores the information like this, ABC, and I just want the text in between.
simple demo
declare #test table
(
xmlElement varchar(1000)
)
insert into #test
values ('<PersonNumber>013870</PersonNumber>')
-- select numbers from xml in the given format
select
cast(SUBSTRING(xmlElement, 15 , CHARINDEX('</PersonNumber>',xmlElement)-15) as int) -- 15 is position where number starts, because 14 is legth of <PersonNumber>
from #test
-- result is 13870
In Oracle there is *REGEXP_SUBSTR* you can use it if you are oracle to get the number you want ans this is an example for you:
SELECT
REGEXP_SUBSTR('500 Oracle Parkway, Redwood Shores, CA',
',[^,]+,') "REGEXPR_SUBSTR"
FROM DUAL;
REGEXPR_SUBSTR
-----------------
, Redwood Shores,
If PersonNumber is fixed length you can simply use substring function.
Otherwise use
select Substring(PersonNumber, Patindex('%>%',PersonNumber) + 1, Patindex('%< /%',PersonNumber) - Patindex('%>%',PersonNumber)-1)
Try this as Sample:
DECLARE #z VARCHAR(32) = ',ukasd10,';
SELECT REPLACE(SUBSTRING(#z, CHARINDEX(',', #z), LEN(#z)), ',', '') AS Sample
and use this logic wherever you want...thanks!
With SQL Server, you can use an XML method if the column contains well-formed XML:
SELECT CAST(YourColumn AS xml).value('/Request[1]/Schedule[1]/Employees[1]/PersonIdentity[1]/PersonNumber[1]', 'int') AS PersonNumber
FROM dbo.YourTable;

Return Comma separated values SQL [duplicate]

This question already has answers here:
How to make a query with group_concat in sql server [duplicate]
(4 answers)
Closed 9 years ago.
I have a field names DAILYREPORT.WEATHERCONDITION which can hold values as '1,2,3' or '1' or '2,4' based on what the user selects from the list of weather check boxes available to him. The weather table contains the list of weathers which he selects
Weather Table
ID Condition
----------
1 Sunny
2 Cloudy
3 Fine
4 Windy
Now i need a query which returns the conditions as 'Sunny,Cloudy,Fine' when DAILYREPORT.WEATHERCONDION=1,2,3
Try this :
SELECT STUFF
(
(select ',' + Condition
from
Weather
where
ID in (1,2,3)
FOR XML PATH('')
),1,1,''
)
DECLARE #list VARCHAR(MAX)
SELECT #list = COALESCE(#list+',' ,'') + Condition
FROM Weather
WHERE ID IN (1,2,3)
SELECT #list
You declare a #list variable of varchar type. Then using the COALESCE expression (please look here http://msdn.microsoft.com/en-us/library/ms190349.aspx for further details on how it works) you get what you want.
That's a SQL fiddle that show that the above works as it is expected
http://sqlfiddle.com/#!6/65df2/1
Note : In order to avoid any misconception, I don't say that the COALESCE solves the stated problem.
It is is only there to deal with initializing the string and the issue
of a extra comma at the end.
as Mikael wrote below.
mine is same as krishna,
Declare #Weather Table (ID int, Condition varchar(50))
insert into #Weather values(1,'Sunny'),(2,'Cloudy'),(3,'Fine'),(4,'Windy')
select top 1
stuff((select ','+Condition from #Weather b where id in(1,2,3) for xml path('')),1,1,'')Condition
from #Weather
Try this i hope it is useful to Your
select SUBSTRING(
(select ','+ s.condition from DAILYREPORT s where id in (1,2,3) order by condition for xml path('')),2,200000) as CSV

TSQL how do you iterate through rows while parsing them?

Sorry for the poor question wording I wasn't sure how to describe this. I want to iterate through every row in a table and while doing so, extract a column, parse the varchar that is in it and depending on what it finds insert rows into another table. Something along the lines of this:
DECLARE #string varchar(max);
foreach row in (select * from Table) {
set #string = row[column];
while (len(#string) > 0) {
-- Do all the parsing in here
if (found what was looking for)
insert into Table2 values(row[column2], row[column3]);
}
}
It would be really nice for this to be a stored procedure so for it to be done in SQL. I'm just not too sure on how to approach it. Thanks.
Edit:
This is basically the functionality I was hoping for:
Table 1 |
id_number | text |
1 Hello, test 532. Yay oh and test 111
2 test 932.
3 This is a test 315 of stuff test 555.
4 haflksdhfal test 311 sadjhfalsd
5 Yay.
I want to go through this table and parse all of the text columns to look for instances of 'test #' where # is a number. When it finds something inside of the text in that format it will insert that value into another table like:
Table 2 |
id_number | number
1 532
1 111
2 932
3 315
3 555
4 311
You are thinking procedurally instead of set based. You can probably write the whole thing as a single query:
INSERT INTO target_table (column list)
SELECT (column list)
FROM source_table
WHERE (parse your column) = (some criterion)
It is much easier to write, and probably a lot faster too.
If your parsing function is complicated, you can use put it into a user defined function instead of embedding it directly into the query.
In SQL Server 2008 you can do this
WITH testTable AS
(
SELECT 1 AS id_number, N'Hello, test 532. Yay oh and test 111' AS txt UNION ALL
SELECT 2, N'test 932.' UNION ALL
SELECT 3, N'This is a test 315 of stuff test 555.' UNION ALL
SELECT 4, N'haflksdhfal test 311 sadjhfalsd' UNION ALL
SELECT 5, N'Yay.'
)
SELECT id_number,display_term
FROM testTable
CROSS APPLY sys.dm_fts_parser('"' + REPLACE(txt,'"','""') + '"', 1033, 0,0)
WHERE TXT IS NOT NULL and
display_term NOT LIKE '%[^0-9]%' /*Or use LIKE '[0-9][0-9][0-9]' to only get 3
digit numbers*/
Returns
id_number display_term
----------- ------------------------------
1 532
1 111
2 932
3 315
3 555
4 311
Something like this is you always have "Test (number)". It works on SQL Server 2005+
DECLARE #Table1 TABLE (id_number int, textcol nvarchar(MAX))
INSERT #Table1 VALUES (1, 'Hello, test 532. Yay oh and test 111')
INSERT #Table1 VALUES (2, 'test 932.')
INSERT #Table1 VALUES (3, 'This is a test 315 of stuff test 555.')
INSERT #Table1 VALUES (4, 'haflksdhfal test 311 sadjhfalsd')
INSERT #Table1 VALUES (5, 'Yay.')
;WITH cte AS
(
SELECT TOP 9999 CAST(ROW_NUMBER() OVER (ORDER BY c1.OBJECT_ID) AS varchar(6)) AS TestNum
FROM sys.columns c1 CROSS JOIN sys.columns c2
)
SELECT id_number, TestNum FROM
cte
JOIN
#Table1 ON PATINDEX('%Test ' + TestNum + '[^0-9]%', textcol) > 0
OR textcol LIKE '%Test ' + TestNum
ORDER BY
id_number
The feature you are looking for is called a CURSOR - here is an article on how to use them.
They are considered bad for performance and difficult to use correctly.
Rethink your problem and restate it so it can be solved in a set based operation.
Look at using table variables or sub queries for your complex condition.
You're after a cursor - see the MSDN docs here. Note that cursors should be avoided wherever possible - there are very few places that they're appropriate and can result in slow inefficient code - you're usually better off trying a set-based solution.
To do this as you request, with iteration you can do it using a Cursor, using your sample information below is how a cursor is laid-out. You put your row-by-row process where my comment is.
DECLARE #CurrentRecord VARCHAR(MAX)
DECLARE db_cursor CURSOR FOR
SELECT Column
FROM Table
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #CurrentRecord
WHILE ##FETCH_STATUS = 0
BEGIN
--Your stuff here
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
However, depending on what you are doing, and if this is something that you do on a regular basis. I would recommend seeing if you can extract the parsing out to a User Defined Function, then you could make it set based, and not use a cursor. As a cursor should be a "last ditch" effort.

SQL Inline or Scalar Function?

So I need an SQL function that will concatenate a bunch of row values into one varchar.
I have the functions written but right now I'm focused on what is the better choice for performance.
The Scalar Function is
CREATE FUNCTION fn_GetPatients_ByRecipient (#recipient int)
RETURNS varchar(max)
AS
BEGIN
DECLARE #patients varchar(max)
SET #patients = ''
SELECT #patients = #patients + convert(varchar, Patient) + ';' FROM RecipientsPatients WHERE Recipient = #recipient
RETURN #patients
END
The Inline Function just returns a table of all the values instead of concatenating them.
CREATE FUNCTION fn_GetPatients_ByRecipient (#recipient int)
RETURNS TABLE
AS
RETURN
(
SELECT Patient FROM RecipientsPatients WHERE Recipient = #recipient
)
I would then take this table in a separate function and concatenate them together. I was thinking the second choice is best since I will be going row by row through a smaller data set. Any opinions on what I'm doing right/wrong would be appreciated.
Thanks
This problem of string concatenation in SQL Server has several solutions, and the pros and cons are discussed in Concatenating Row Values in Transact-SQL and other similar articles on the web.
My favourite solution is using the FOR XML PATH(' ') trick. The chain assignment method you use works fine, although is not officialy supported and hence may break in future. Your method should be among the fastest possible, if not the fastes, as long as the table valued function does not perform a full scan, ie. you have an index on Recipient that covers Patient (use include).
The only thing I would add is to declare both functions WITH SCHEMABINDING, this has side effects that improve performance.
See here for an example of using the FOR XML PATH trick
set nocount on;
declare #t table (id int, name varchar(20), x char(1))
insert into #t (id, name, x)
select 1,'test1', 'a' union
select 1,'test1', 'b' union
select 1,'test1', 'c' union
select 2,'test2', 'a' union
select 2,'test2', 'c' union
select 3,'test3', 'b' union
select 3,'test3', 'c'
SELECT p1.id, p1.name,
stuff((SELECT ', ' + x
FROM #t p2
WHERE p2.id = p1.id
ORDER BY name, x
FOR XML PATH('') ), 1,2, '') AS p3
FROM #t p1
GROUP BY
id, name
it returns
1 test1 a, b, c
2 test2 a, c
3 test3 b, c
Have a look at Adam Machanic's results from his Grouped String Concatenation Contest:
http://web.archive.org/web/20150328021904/http://sqlblog.com/blogs/adam_machanic/archive/2009/05/31/grouped-string-concatenation-the-winner-is.aspx
It has the code to show you the most efficient way to do this. Peter Larsson, who won the contest, used a combination of tricks including XML PATH to accomplish the task. There was some debate later about whether it was the most efficient solution based on subsequent tests of other submissions. Make sure you check the comments to know what scripts to look at in the zip file you can download there. Generally FOR XML PATH('') is the fastest though.