How to separate values with Parse name in SQL Server - sql

I have a value (500 , 850 , 65.5) as GivenUnitPrice and I want to separate these by making separate columns by PARSENAME
I have tried like this
PARSENAME(GivenUnitPrice, 3) as DB,
PARSENAME(GivenUnitPrice, 2) as Owner,
PARSENAME(GivenUnitPrice, 1) as Object
and the result is
DB | Owner | Object
NULL | 500 , 850 , 65 | 5

Seems you want to seperate the characters by commas but Parsename() function splits by dot character( e.g. decimal number 65.5 is also splitted as if seperate integers ), so yields wrong results for your case. It's better to use replace(),substring() and charindex() together as :
with t as
(
select replace(replace('500 , 850 , 65.5',')',''),'(','') as GivenUnitPrice
), t2 as
(
select substring(GivenUnitPrice,1,charindex(',',GivenUnitPrice)-1) as db,
substring(GivenUnitPrice,charindex(',',GivenUnitPrice)+1,len(GivenUnitPrice)) as owner_object
from t
)
select db,
substring(owner_object,1,charindex(',',owner_object)-1) as owner,
substring(owner_object,charindex(',',owner_object)+1,len(owner_object)) as object
from t2;
db owner object
500 850 65.5
Demo

DECLARE #GivenUnitPrice VARCHAR(100)= '500 , 850 , 65.5'
SELECT PARSENAME(replacE(#GivenUnitPrice,',','.'),4) as DB,PARSENAME(replacE(#GivenUnitPrice,',','.'),3) as Owner,PARSENAME(replacE(#GivenUnitPrice,',','.'),2)+ '.'+PARSENAME(#GivenUnitPrice,1) AS OBJECT

You can try this....
DECLARE #UnitPrice VARCHAR(100)
SET #UnitPrice= '500 , 850 , 65.5'
SELECT PARSENAME(REPLACE(#UnitPrice,',','.'),4) as DB,
PARSENAME(REPLACE(#UnitPrice,',','.'),3) as Owner,
PARSENAME(REPLACE(#UnitPrice, ',', '.'), 2) AS OBJECT,
PARSENAME(REPLACE(#UnitPrice, '', '.'), 1) AS OBJECT

PARSENAME basically consider .(Dot) as a delimeter in the string. In your input string, there are only one .(Dot) available at the end and as a result you are getting values only at Owner and Object column. IF you want to use PARSENAME for this string, please replace commas with .(Dot) first and then apply PARSENAME as below-
DECLARE #ObjectName NVARCHAR(1000);
SET #ObjectName = '500 , 850 , 65.5';
SET #ObjectName = REPLACE(#ObjectName, ',', '.');
SELECT PARSENAME(#ObjectName, 4) AS Server,
PARSENAME(#ObjectName, 3) AS DB,
PARSENAME(#ObjectName, 2) AS Owner,
PARSENAME(#ObjectName, 1) AS Object;

Related

Is there a way to find default values that is a combination of the same number like 000/000/0 or 11111 or 99999?

I want to find values in the SQL database that is a combination of the same number such as 0000 or 000/000/0 or 11111 or 99999 etc.
Is there a way to find these values without hardcoding?
What I am currently doing is:
select * from XXXX where value = '000/000/0'
A simple solution is to remove all instances of first character of the string, and check if the result is an empty string:
select *
from t
where replace(replace(str, '/', ''), substring(str, 1, 1), '') = ''
Try this on :
SELECT *
FROM XXXX
WHERE value IN ('000/000/0',11111,99999,0000)
If you need fill column values with application or other third-party. you can use stored procedure like below:
CREATE PROC dbo.usp_ListOfNumbers #NumberValues Nvarchar(200)
as
BEGIN
SELECT *
FROM XXXX
WHERE value = #NumberValues
END
for call just use
EXEC dbo.usp_ListOfNumbers #NumberValues = '000/000/0'

String aggregation using JSON in SQL Server 2016

I would like to format a json string '[{"_":7},{"_":13},{"_":17}]' as '[7,13,17]'
Tried with REPLACE Method in TSQL. I have to use REPLACE method three times to get the desire result.
SELECT REPLACE(REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','},{"_":',', '),'{"_":',''),'}','')
is there a better way to do that?
I am using SQL Server 2016.
After some comments for this post, This my actual issue.
I have some customer data. Customer Table
CustomerId | Name
1 ABC
2 XYZ
3 EFG
each customer has some area of interest. Customer Area of Interest
CustomerAreaInterestId | FK_CustomerId | FK_AreaOfInterestId
1 1 2
2 1 3
3 1 5
4 2 1
5 2 2
6 3 3
7 3 4
Area of interest table
AreaOfInterestId | Description
1 Interest1
2 Interest2
3 Interest3
4 Interest4
5 Interest5
In the final result set, I have to include area of interest id's as an array of value
[
{
"CustomerName": "ABC",
"AreaofInterest": "[2,3,5]"
},
{
"CustomerName": "XYZ",
"AreaofInterest": "[1,2]"
},
{
"CustomerName": "EFG",
"AreaofInterest": "[3,4]"
}
]
The result consists with some other data’s as well. I have omitted for the code brevity.
Short Version
Cast the numeric field to text before trying to aggregate it
From the comments, it looks like the real question is how to use JSON to aggregate strings in SQL Server 2016, as shown in this answer.
SELECT
JSON_VALUE(
REPLACE(
(SELECT _ = someField FROM someTable FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._'
)
or, rewritten for clarity :
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = someField
FROM someTable
FOR JSON PATH)
,'"},{"_":"',', ')
,'$[0]._')
That query works only with string fields. One needs to understand what it does before it can be adopted to other types.
The inner query generates a JSON string from a field's values, eg '[{"_":"value1"},{"_":"value2"}]'.
REPLACE replaces the quotes and separators between objects, changing that array of objects to '[{"_":"value1,value2"}]'. That's a single object in an array, whose single attribute is a comma-separated string.
JSON_VALUE(...,,'$[0]._') extracts the _ attribute of that single array item.
That trick can't be used with numeric values because they don't have quotes. The solution is to cast them to text first:
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = CAST(someNumber as nvarchar(20))
FROM someTable
FOR JSON PATH)
,'"},{"_":"',', ')
,'$[0]._')
Eg :
declare #t table (id int)
insert into #t
values
(7),
(13),
(17)
SELECT
JSON_VALUE( REPLACE(
(SELECT _ = cast(ID as nvarchar(20))
FROM #t
FOR JSON PATH)
,'"},{"_":"',', '),'$[0]._')
The only change from the original query is the cast clause.
This produces :
7, 13, 17
This conversion is localized so care must be taken with decimals and dates, to avoid producing unexpected results, eg 38,5, 40,1 instead of 38.5, 40.1.
PS: That's no different than the XML technique, except STUFF is used there to cut off the leading separator. That technique also needs casting numbers to text, eg :
SELECT STUFF(
( SELECT N', ' + cast(ID as nvarchar(20))
FROM #t FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),
1,2,N'')
If you want to use only JSON functions (not string-based approach), the next example may help:
DECLARE #json nvarchar(max) = N'[{"_":7},{"_":13},{"_":17}]'
DECLARE #output nvarchar(max) = N'[]'
SELECT #output = JSON_MODIFY(#output, 'append $', j.item)
FROM OPENJSON(#json) WITH (item int '$."_"') j
SELECT #output AS [Result]
Result:
Result
[7,13,17]
Of course, the approach based on string aggregation is also a possible solution:
DECLARE #json nvarchar(max) = N'[{"_":7},{"_":13},{"_":17}]'
SELECT CONCAT(
N'[',
STUFF(
(
SELECT CONCAT(N',', j.item)
FROM OPENJSON(#json) WITH (item int '$."_"') j
FOR XML PATH('')
), 1, 1, N''
),
N']'
)
Yes you could do it with only 2 replace :
SELECT REPLACE(REPLACE('[{"_":7},{"_":13},{"_":17}]','{"_":',''),'}','')
DEMO HERE
Except if you really need a space after coma which is not what you asked to be honest.

How to remove character from an SQL query in where condition

I got some dirty database of SQL to do a task. I have a column which can have data from different format like the following:
format 1 = 0000-0000000
format 2 = 0000.0000000
format 3 = 00000000000
The format 3 is a good format for my query.
$sql = "SELECT * from table where col='00000000000'"
I want to to remove these character in select query without disturbing the actual data.
Seems you need Replace function. Just remove extra symbols during comparison
SELECT * from table
where replace(replace(col, '-', ''), '.', '') ='00000000000'
There is a function to format the string:
create FUNCTION [dbo].[fn_StripString](#value as varchar(80), #KeepValues as varchar(80))
RETURNS varchar(80)
AS
begin
While PatIndex(#KeepValues, #value) > 0
Set #value = Stuff(#Valor, PatIndex(#KeepValues, #value), 1, '')
return #value
end
Then, assuming you just want numeric values:
SELECT *
from table
where dbo.fn_StripString(col, '%[^0-9]%') = '00000000000'
Use IN query
Select * from table where col in ('00000000000','0000.0000000','0000-0000000')

SQL Server - Select column that contains query string and split values into anothers 'columns'

I need to do a select in a column that contains a query string like:
user_id=300&company_id=201503&status=WAITING OPERATION&count=1
I want to perform a select and break each value in a new column, something like:
user_id | company_id | status | count
300 | 201503 | WAITING OPERATION | 1
How can i do it in SQL Server without use procs?
I've tried a function:
CREATE FUNCTION [xpto].[SplitGriswold]
(
#List NVARCHAR(MAX),
#Delim1 NCHAR(1),
#Delim2 NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
SELECT
Val1 = PARSENAME(Value,2),
Val2 = PARSENAME(Value,1)
FROM
(
SELECT REPLACE(Value, #Delim2, '&') FROM
(
SELECT LTRIM(RTRIM(SUBSTRING(#List, [Number],
CHARINDEX(#Delim1, #List + #Delim1, [Number]) - [Number])))
FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_objects) AS x
WHERE Number <= LEN(#List)
AND SUBSTRING(#Delim1 + #List, [Number], LEN(#Delim1)) = #Delim1
) AS y(Value)
) AS z(Value)
);
GO
Execution:
select QueryString
from User.Log
CROSS APPLY notifier.SplitGriswold(REPLACE(QueryString, ' ', N'ŏ'), N'ŏ', '&') AS t;
But it returns me only one column with all inside:
QueryString
user_id=300&company_id=201503&status=WAITING OPERATION&count=1
Thanks in advance.
I've had to do this many times before, and you're in luck! Since you only have 3 delimiters per string, and that number is fixed, you can use SQL Server's PARSENAME function to do it. That's far less ugly than the best alternative (using the XML parsing stuff). Try this (untested) query (replace TABLE_NAME and COLUMN_NAME with the appropriate names):
SELECT
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),1) AS 'User',
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),2) AS 'Company_ID',
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),3) AS 'Status',
PARSENAME(REPLACE(COLUMN_NAME,'&','.'),4) AS 'Count',
FROM TABLE_NAME
That'll get you the results in the form "user_id=300", which is far and away the hard part of what you want. I'll leave it to you to do the easy part (drop the stuff before the "=" sign).
NOTE: I can't remember if PARSENAME will freak out over the illegal name character (the "=" sign). If it does, simply nest another REPLACE in there to turn it into something else, like an underscore.
You need to use SQL SUBSTRING as part of your select statement. You would first need to build the first row, then use a UNION to return the second row.

Uppercase first two characters in a column in a db table

I've got a column in a database table (SQL Server 2005) that contains data like this:
TQ7394
SZ910284
T r1534
su8472
I would like to update this column so that the first two characters are uppercase. I would also like to remove any spaces between the first two characters. So T q1234 would become TQ1234.
The solution should be able to cope with multiple spaces between the first two characters.
Is this possible in T-SQL? How about in ANSI-92? I'm always interested in seeing how this is done in other db's too, so feel free to post answers for PostgreSQL, MySQL, et al.
Here is a solution:
EDIT: Updated to support replacement of multiple spaces between the first and the second non-space characters
/* TEST TABLE */
DECLARE #T AS TABLE(code Varchar(20))
INSERT INTO #T SELECT 'ab1234x1' UNION SELECT ' ab1234x2'
UNION SELECT ' ab1234x3' UNION SELECT 'a b1234x4'
UNION SELECT 'a b1234x5' UNION SELECT 'a b1234x6'
UNION SELECT 'ab 1234x7' UNION SELECT 'ab 1234x8'
SELECT * FROM #T
/* INPUT
code
--------------------
ab1234x3
ab1234x2
a b1234x6
a b1234x5
a b1234x4
ab 1234x8
ab 1234x7
ab1234x1
*/
/* START PROCESSING SECTION */
DECLARE #s Varchar(20)
DECLARE #firstChar INT
DECLARE #secondChar INT
UPDATE #T SET
#firstChar = PATINDEX('%[^ ]%',code)
,#secondChar = #firstChar + PATINDEX('%[^ ]%', STUFF(code,1, #firstChar,'' ) )
,#s = STUFF(
code,
1,
#secondChar,
REPLACE(LEFT(code,
#secondChar
),' ','')
)
,#s = STUFF(
#s,
1,
2,
UPPER(LEFT(#s,2))
)
,code = #s
/* END PROCESSING SECTION */
SELECT * FROM #T
/* OUTPUT
code
--------------------
AB1234x3
AB1234x2
AB1234x6
AB1234x5
AB1234x4
AB 1234x8
AB 1234x7
AB1234x1
*/
UPDATE YourTable
SET YourColumn = UPPER(
SUBSTRING(
REPLACE(YourColumn, ' ', ''), 1, 2
)
)
+
SUBSTRING(YourColumn, 3, LEN(YourColumn))
UPPER isn't going to hurt any numbers, so if the examples you gave are completely representative, there's not really any harm in doing:
UPDATE tbl
SET col = REPLACE(UPPER(col), ' ', '')
The sample data only has spaces and lowercase letters at the start. If this holds true for the real data then simply:
UPPER(REPLACE(YourColumn, ' ', ''))
For a more specific answer I'd politely ask you to expand on your spec, otherwise I'd have to code around all the other possibilities (e.g. values of less than three characters) without knowing if I was overengineering my solution to handle data that wouldn't actually arise in reality :)
As ever, once you've fixed the data, put in a database constraint to ensure the bad data does not reoccur e.g.
ALTER TABLE YourTable ADD
CONSTRAINT YourColumn__char_pos_1_uppercase_letter
CHECK (ASCII(SUBSTRING(YourColumn, 1, 1)) BETWEEN ASCII('A') AND ASCII('Z'));
ALTER TABLE YourTable ADD
CONSTRAINT YourColumn__char_pos_2_uppercase_letter
CHECK (ASCII(SUBSTRING(YourColumn, 2, 1)) BETWEEN ASCII('A') AND ASCII('Z'));
#huo73: yours doesn't work for me on SQL Server 2008: I get 'TRr1534' instead of 'TR1534'.
update Table set Column = case when len(rtrim(substring (Column , 1 , 2))) < 2
then UPPER(substring (Column , 1 , 1) + substring (Column , 3 , 1)) + substring(Column , 4, len(Column)
else UPPER(substring (Column , 1 , 2)) + substring(Column , 3, len(Column) end
This works on the fact that if there is a space then the trim of that part of string would yield length less than 2 so we split the string in three and use upper on the 1st and 3rd char. In all other cases we can split the string in 2 parts and use upper to make the first two chars to upper case.
If you are doing an UPDATE, I would do it in 2 steps; first get rid of the space (RTRIM on a SUBSTRING), and second do the UPPER on the first 2 chars:
// uses a fixed column length - 20-odd in this case
UPDATE FOO
SET bar = RTRIM(SUBSTRING(bar, 1, 2)) + SUBSTRING(bar, 3, 20)
UPDATE FOO
SET bar = UPPER(SUBSTRING(bar, 1, 2)) + SUBSTRING(bar, 3, 20)
If you need it in a SELECT (i.e. inline), then I'd be tempted to write a scalar UDF