How to Add all values given in comma separated in sql - sql

How to get the SUM of values of one column in table. Now I want get the SUM of 8 and 0 if I use query write below.
SELECT SUM(Items) FROM dbo.CustomSplit(#AssigneeProgress,',')
this gives an error
Operand data type varchar is invalid for sum operator.
My code is:
DECLARE #AssigneeProgress AS VARCHAR(100)
SELECT
#AssigneeProgress = STUFF((SELECT ',' + CAST(ISNULL((((TblAssignments.PlannedDuration * 100) / 300) * TblAssignments.Progress) / 100,0) AS VARCHAR(100))
FROM TblTasks,TblAssignments
WHERE TblTasks.TaskId = TblAssignments.AssignmentEntityId
AND TblAssignments.AssignmentEntity = 'Task'
AND AssignmentStatus NOT IN ('Deleted','Cancelled')
AND TblTasks.TaskId = 63 FOR XML PATH('')), 1, 1,'')
SELECT * FROM dbo.CustomSplit(#AssigneeProgress,',')
This query gives me the result in table like
Items
8
0

Does your method CustomSplit return a table having the column Items of type varchar?
If yes, you can convert the column:
SELECT SUM(cast(Items as int)) FROM dbo.CustomSplit(#AssigneeProgress,',')

Try to cast the Items that you get back from your split function to an INT type before summing:
SELECT
SUM(CAST(Items AS INT))
FROM
dbo.CustomSplit(#AssigneeProgress,',')
The CustomSplit function most likely returns varchar(x) items....

Related

Convert Column Values into comma separated str

I have a table #f with the following data
ID
Number
V2
28
V2
29
V2
30
I would like my desired output to have
ID
Number
V2
28,29,30
How could I achieve this?
I've tried using the STUFF function but I get an error
Error converting data type varchar to numeric.
This is the code I have:
SELECT
#f.id,
number = STUFF((SELECT DISTINCT ',' + f.id
FROM #f f
WHERE f.number = number
FOR XML PATH('')), 1, 1, '')
FROM
#f
GROUP BY
#f.id
Here's a simple solution utilizing string_agg.
select ID
,string_agg(Number, ',') as Number
from t
group by ID
ID
Number
V2
28,29,30
Fiddle

CHARINDEX not able to retrieve index in a string

If we have a query as shown below, where the CHARINDEX is supposed to find the index of string in a given column, but the result is not as expected. Is there any other way to retrieve the index?
SELECT t.*, CHARINDEX('text', CAST([col] AS varchar)) AS [out]
FROM (
SELECT CAST([col] AS NVARCHAR(4000)) AS [col]
FROM (
VALUES ('"http:\/\/xxxxx.share.com\/text"'),
('random content in string :\/\\//\ / text \\\''''''')
) AS t0([col])
) t
the result is
col | out
"http:\/\/xxxxx.share.com\/text" | 0
random content in string :\/\\//\ / text \\\'''''' | 0
But if I expect the output to be like
col | out
"http:\/\/xxxxx.share.com\/text" | 28
random content in string :\/\\//\ / text \\\'''''' | 36
As the text char is in 28/36 in the rows respectively, how do we fetch the index position in this case?
Remove the CAST Function in your Query.
There is no need for Converting the Data type to VARCHAR here. Because it is already Converted into NVARCHAR(4000) in the below select Statement.
If you need so the use CAST([col] AS varchar(max))) instead of CAST([col] AS varchar)).
SELECT t.*, CHARINDEX('text', [col] ) AS [out]
FROM (
SELECT CAST([col] AS NVARCHAR(4000)) AS [col]
FROM (
VALUES ('"http:\/\/xxxxx.share.com\/text"'),
('random content in string :\/\\//\ /text \\\''''''')
) AS t0([col])
) t
Your problem is almost a typo, and you are casting to VARCHAR, which may not be the appropriate length to actually fit all your data. Just cast to a length long enough to accommodate your data, and your query should work:
SELECT t.*, CHARINDEX('text', CAST([col] AS varchar(255))) AS [out] -- change is here
FROM (
SELECT CAST([col] AS NVARCHAR(4000)) AS [col]
FROM (
VALUES ('"http:\/\/xxxxx.share.com\/text"'),
('random content in string :\/\\//\ / text \\\''''''')
) AS t0([col])
) t
Demo

SQL Server: Select rows with multiple occurrences of regex match in a column

I’m fairly used to using MySQL, but not particularly familiar with SQL Server. Tough luck, the database I’m dealing with here is on SQL Server 2014.
I have a table with a column whose values are all integers with leading, separating, and trailing semicolons, like these three fictitious rows:
;905;1493;384;13387;29;933;467;28732;
;905;138;3084;1387;290;9353;4767;2732;
;9085;14493;3864;130387;289;933;4767;28732;
What I am trying to do now is to select all rows where more than one number taken from a list of numbers appears in this column. So for example, given the three rows above, if I have the group 905,467,4767, the statement I’m trying to figure out how to construct should return the first two rows: the first row contains 905 and 467; the second row contains 905 and 4767. The third row contains only 4767, so that row should not be returned.
As far as I can tell, SQL Server does not actually support regex directly (and I don’t even know what managed code is), which doesn’t help. Even with regex, I wouldn’t know where to begin. Oracle seems to have a function that would be very useful, but that’s Oracle.
Most similar questions on here deal with finding multiple instances of the same character (usually singular) and solve the problem by replacing the string to match with nothing and counting the difference in length. I suppose that would technically work here, too, but given a ‘filter’ group of 15 numbers, the SELECT statement would become ridiculously long and convoluted and utterly unreadable. Additionally, I only want to match entire numbers (so if one of the numbers to match is 29, the value 29 would match in the first row, but the value 290 in the second row should not match), which means I’d have to include the semicolons in the REPLACE clause and then discount them when calculating the length. A complete mess.
What I would ideally like to do is something like this:
SELECT * FROM table WHERE REGEXP_COUNT(column, ';(905|467|4767);') > 1
– but that will obviously not work, for all kinds of reasons (the most obvious one being the nonexistence of REGEXP_COUNT outside Oracle).
Is there some sane, manageable way of doing this?
You can do
SELECT *
FROM Mess
CROSS APPLY (SELECT COUNT(*)
FROM (VALUES (905),
(467),
(4767)) V(Num)
WHERE Col LIKE CONCAT('%;', Num, ';%')) ca(count)
WHERE count > 1
SQL Fiddle
Or alternatively
WITH Nums
AS (SELECT Num
FROM (VALUES (905),
(467),
(4767)) V(Num))
SELECT Mess.*
FROM Mess
CROSS APPLY (VALUES(CAST(CONCAT('<x>', REPLACE(Col, ';', '</x><x>'), '</x>') AS XML))) x(x)
CROSS APPLY (SELECT COUNT(*)
FROM (SELECT n.value('.', 'int')
FROM x.x.nodes('/x') n(n)
WHERE n.value('.', 'varchar') <> ''
INTERSECT
SELECT Num
FROM Nums) T(count)
HAVING COUNT(*) > 1) ca2(count)
Could you put your arguments into a table (perhaps using a table-valued function accepting a string (of comma-separated integers) as a parameter) and use something like this?
DECLARE #T table (String varchar(255))
INSERT INTO #T
VALUES
(';905;1493;384;13387;29;933;467;28732;')
, (';905;138;3084;1387;290;9353;4767;2732;')
, (';9085;14493;3864;130387;289;933;4767;28732;')
DECLARE #Arguments table (Arg int)
INSERT INTO #Arguments
VALUES
(905)
, (467)
, (4767)
SELECT String
FROM
#T
CROSS JOIN #Arguments
GROUP BY String
HAVING SUM(CASE WHEN PATINDEX('%;' + CAST(Arg AS varchar) + ';%', String) > 0 THEN 1 ELSE 0 END) > 1
And example of using this with a function to generate the arguments:
CREATE FUNCTION GenerateArguments (#Integers varchar(255))
RETURNS #Arguments table (Arg int)
AS
BEGIN
WITH cte
AS
(
SELECT
PATINDEX('%,%', #Integers) p
, LEFT(#Integers, PATINDEX('%,%', #Integers) - 1) n
UNION ALL
SELECT
CASE WHEN PATINDEX('%,%', SUBSTRING(#Integers, p + 1, LEN(#Integers))) + p = p THEN 0 ELSE PATINDEX('%,%', SUBSTRING(#Integers, p + 1, LEN(#Integers))) + p END
, CASE WHEN PATINDEX('%,%', SUBSTRING(#Integers, p + 1, LEN(#Integers))) = 0 THEN RIGHT(#Integers, PATINDEX('%,%', REVERSE(#Integers)) - 1) ELSE LEFT(SUBSTRING(#Integers, p + 1, LEN(#Integers)), PATINDEX('%,%', SUBSTRING(#Integers, p + 1, LEN(#Integers))) - 1) END
FROM cte
WHERE p <> 0
)
INSERT INTO #Arguments (Arg)
SELECT n
FROM cte
RETURN
END
GO
DECLARE #T table (String varchar(255))
INSERT INTO #T
VALUES
(';905;1493;384;13387;29;933;467;28732;')
, (';905;138;3084;1387;290;9353;4767;2732;')
, (';9085;14493;3864;130387;289;933;4767;28732;')
;
SELECT String
FROM
#T
CROSS JOIN GenerateArguments('905,467,4767')
GROUP BY String
HAVING SUM(CASE WHEN PATINDEX('%;' + CAST(Arg AS varchar) + ';%', String) > 0 THEN 1 ELSE 0 END) > 1
You can achieve this using the like function for the regex and row_number to determine the number of matches.
Here we declare the column values for testing:
DECLARE #tbl TABLE (
string NVARCHAR(MAX)
)
INSERT #tbl VALUES
(';905;1493;384;13387;29;933;467;28732;'),
(';905;138;3084;1387;290;9353;4767;2732;'),
(';9085;14493;3864;130387;289;933;4767;28732;')
Then we pass your search parameters into a table variable to be joined on:
DECLARE #search_tbl TABLE (
search_value INT
)
INSERT #search_tbl VALUES
(905),
(467),
(4767)
Finally we join the table with the column to search for onto the search table. We apply the row_number function to determine the number of times it matches. We select from this subquery where the row_number = 2 meaning that it joined at least twice.
SELECT
string
FROM (
SELECT
tbl.string,
ROW_NUMBER() OVER (PARTITION BY tbl.string ORDER BY tbl.string) AS rn
FROM #tbl tbl
JOIN #search_tbl search_tbl ON
tbl.string LIKE '%;' + CAST(search_tbl.search_value AS NVARCHAR(MAX)) + ';%'
) tbl
WHERE rn = 2
You could build a where clause like this :
WHERE
case when column like '%;905;%' then 1 else 0 end +
case when column like '%;467;%' then 1 else 0 end +
case when column like '%;4767;%' then 1 else 0 end >= 2
The advantage is that you do not need a helper table. I don't know how you build the query, but the following also works, and is useful if the numbers are in a tsql variable.
case when column like ('%;' + #n + ';%') then 1 else 0 end

trim sql variant

I have column sql variant, which has the following meanings: 100, 150, D1
I'm trying to convert all numbers in the columns into letters (such as D1) according to specific logic in case when. But 150 has spaces and the CASE WHEN doesn't work.
Here's the query I'm using:
Select *,
Case When LTrim(Cast(AttributeValue As NVarchar(Max))) Between 0 And 200 Then 'D1'
Else 'Other'
End
From MyTable As SCR With (NoLock);
I tried the following
LTRIM(CAST column AS VARCHAR(MAX))
but now I get error:
Conversion failed when converting the nvarchar value 'D1' to data type int
How can I remove spaces from sql_variant?
As per your comments edited to use BIGINT due to having larger numbers and leave the column the same if it is not BETWEEN 0 and 400
SELECT *
,CASE
WHEN ISNUMERIC(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX)))) = 1
AND CAST(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX))) AS BIGINT) BETWEEN 0 AND 400 THEN 'D1'
ELSE AttributeValue
END
FROM
MyTable AS SCR WITH (NOLOCK)
You can use the ISNUMERIC() function to determine which of your sql_variants are integers and which are not.
The reason your code is failing isn't because of the trim it is because you are comparing a VARCHAR with an INTEGER so SQL is trying to automatically re cast your final string as an integer which in the case of D1 is not numeric so it causes a conversion error.
Also note that you cannot use sql_variant directly in the ISNUMERIC() function so cast to a varchar first.
Here is an entire example of you to show you how it works:
DECLARE #MyTable AS TABLE (AttributeValue SQL_VARIANT)
INSERT INTO #MyTable VALUES
(CAST(' 150' AS VARCHAR(100)))
,(CAST('D1' AS VARCHAR(100)))
SELECT *
,CASE
WHEN ISNUMERIC(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX)))) = 1
AND CAST(LTRIM(CAST(AttributeValue AS NVARCHAR(MAX))) AS INT) BETWEEN 0 AND 200 THEN 'D1'
ELSE 'Other'
END
FROM
#MyTable AS SCR
use sql replace function
select replace(columnnName, ' ', '')

Select and filter nvarchar like a int

I have a nvarchar column BigMacs in table McTable in my MS SQL 2005 database with alfanumeric and numeric values. For example:
132
432adfad
sfs54543
5256
And now i would like to do something like this:
select Convert(BigMacs, int) from McTable
where IsNumerc(BigMacs) = 1 AND Convert(BigMacs, int) > 6
But when I do this i get a error:
Msg 245, Level 16, State 1, Line 41
Conversion failed when converting the nvarchar value '.' to data type int.
On line select.
How to fix this?
This is probably because the IsNumeric function returns true for any value that COULD be converted to a number. Try the following example:
create table McTable (BigMac varchar(255))
insert into McTable select '1p927'
insert into McTable select '1927'
insert into McTable select '1,927'
insert into McTable select '1.927'
select BigMac, isnumeric(BigMac)
from McTable
select BigMac, CAST(BigMac AS DECIMAL)
from McTable
where isnumeric(BigMac) = 1
Even though all rows except the '1p927' are numeric, the cast will fail! This is because '1,927' cannot be converted to a Decimal (on my machine)
IsNumeric doesn't work exactly as specified. As found here, you could use
IsNumeric (data + 'e0')
-Edo
Try this:
SELECT *
FROM (
SELECT REPLACE(BigMacs, ',', '.') AS BigMacs
FROM McTable m
WHERE IsNumerc(BigMacs) = 1
) q
WHERE CAST(BigMacs AS DECIMAL) > 6
IsNumeric will return TRUE on decimal fractions like 1234.1232, but they cannot be converted to INT.
Checking:
WITH McTable AS
(
SELECT '123124,123123' AS BigMacs
)
SELECT *
FROM (
SELECT REPLACE(BigMacs, ',', '.') AS BigMacs
FROM McTable
WHERE IsNumeric(BigMacs) = 1
) q
WHERE CAST(BigMacs AS DECIMAL) > 6
-----------
123124.123123
There are many ways to accomplish this. Both of these work the same. It is best not to use replace in this situation as there are too many unknowns to account for to replace. It is best to filter everything that is NOT what your after.
SELECT
CONVERT(INT,BigMacs) AS BigMacs
FROM
McTable
WHERE
ISNUMERIC(BigMacs) = 1
AND PATINDEX('%[^0-9]%', BigMacs) = 0
SELECT
CONVERT(INT,BigMacs) AS BigMacs
FROM
McTable
WHERE
ISNUMERIC(BigMacs) = 1
AND BigMacs NOT LIKE ('%[^0-9]%')
Note: It helps if people spell ISNUMERIC() correctly. It also helps if you use the correct syntax order on CONVERT()