Dynamic CASE expression [duplicate] - sql

This question already has answers here:
Check if a varchar is a number (T-SQL)
(12 answers)
Closed 5 years ago.
Is there anyway to have a case expression that produces different results based upon a value being an integer or a character.
Tables
ID CODE
1 ABC
2 123
3 YHU
4 456
5 ikl
I was looking for an expression that separated the int and char.
Result e.g.
ID CODE Category
1 ABC Char
2 123 Int
3 YHU Char
4 456 Int
5 ikl Char
my general logic
CASE WHEN CODE = INT THEN 'Int' Else 'Char' end as Category
But i didnt know if this was possible in SQL?
I am looking mainly for a way to recognise whether its int or char
UPDATE:
What is the best way to separate the numbers from char, * and - into 2 different categories using case expression
ID CODE Category
1 * No_NUM
2 123 NUM
3 YHU No_NUM
4 456 NUM
5 ikl No_NUM
6 - No_NUM

You can use SQL ISNUMERIC function.
SELECT ID, CODE, CASE ISNUMERIC(CODE) WHEN 1 THEN 'NUM' ELSE 'No_NUM' END AS Category FROM my_table;
Another Variation with REGEX
SELECT ID, CODE, CASE WHEN CODE LIKE '%[0-9]%' THEN 'NUM' ELSE 'No_NUM' END AS Category FROM my_table;

You could use TRY_CAST (SQL Server 2012+)
SELECT *,
CASE WHEN TRY_CAST(CODE AS INT) IS NOT NULL THEN 'Int' ELSE 'Char' END
FROM tab;
I've assumed that column is NOT NULL.
Rextester Demo
EDIT:
It is just text inside CASE:
SELECT *,
CASE WHEN TRY_CAST(CODE AS INT) IS NOT NULL THEN 'NUM' ELSE 'No_NUM' END
FROM tab;
Rextester Demo 2

Use PATINDEX:
create table #temp ([ID] int, [CODE] nvarchar(5))
insert into #temp values (1, '*')
insert into #temp values (2, '123')
insert into #temp values (3, 'YHU')
insert into #temp values (4, '456')
insert into #temp values (5, 'ikl')
Select ID
, CASE when PATINDEX('%[0-9]%', [code]) = 1 then 'num'
-- when PATINDEX('%[^0-9]%', [code]) = 1 then 'no_num'
-- when PATINDEX('%[A-Z]%', [code]) = 1 then 'char'
-- when PATINDEX('%[^A-Z]%', [code]) = 1 then 'no_char' /*etc..*/
ELSE 'no_num' END AS 'Category'
from #temp

Related

SQL - CASE statement evaluate INTeger [duplicate]

This question already has answers here:
How to determine whether the number is float or integer
(4 answers)
Closed 1 year ago.
In Windows Server SQL, I am trying to change a value if the value from another table is an Integer and not a decimal. If it is a value, then the change within the Case Statement should apply.
I am thinking:
with numberCTE (valuea, valueaa) as (
select (number1 / number2) as valuea, valueaa
from tablea
)
select
CASE when value = INT then 'Apple' else 'Banana' end eval
from
tableb b
join numberCTE a on b.valueaa = a.valueaa
Perhaps using modulus could cut to the chase n % 1
I should note that if calc is a float, it would have to be converted into a decimal
Declare #Table table (calc decimal(25,15))
Insert Into #Table values
(5.000000000000000)
,(4.900000000000000)
,(2.000000000000000)
,(1.212121212121212)
,(1.050000000000000)
,(0.950000000000000)
,(0.900000000000000)
,(0.850000000000000)
,(10.00000000000000)
Select *
,case when calc % 1 = 0
then 'Apple'
else 'Banana'
end
From #Table
Results
calc (No column name)
5.000000000000000 Apple
4.900000000000000 Banana
2.000000000000000 Apple
1.212121212121212 Banana
1.050000000000000 Banana
0.950000000000000 Banana
0.900000000000000 Banana
0.850000000000000 Banana
10.850000000000000 Banana
10.000000000000000 Apple
You need something like this :
When value is INT = Apple , else = Banana
Declare #table table (IntCol nvarchar(6),DecCol nvarchar(6))
insert into #table
select '10','10.45' union all
select '10.00','10.+0' union all
select '45.23','10,478' union all
select '48.7','78.8.5' union all
select '1','14.0' union all
select '0','10.788' union all
select '100','45.89'
select IntCol from #table
select
CASE
WHEN IntCol -floor(IntCol) =0 THEN 'Apple'
WHEN IntCol NOT LIKE '%[^0-9]%' THEN 'Apple'
WHEN IntCol LIKE '%[^0-9]%' THEN 'Banana'
END AS 'IsIntiger?'
from #table
OUTPUT looks like :
#EDIT i just added WHEN IntCol -floor(IntCol) =0 THEN 'Apple'
and there you go what you expected , hope i helped you :)

Increment by on substring -SQL

I have a list of strings like so:
M308_7
M308_8
M308_9
M308_10
and want to grab the MAX number from the last digits after the "_" of the string and increment this number by one (so the number it should return is 11)
I read on other posts to convert the last digits to integers as 9 is higher than 10 in alphabetical and that was the reason for it returning _9 as the MAX.
I have done this but still the value being returned is 9 when it should be 10
See below what I have so far..
select
#BomNo = MAX(case when CHARINDEX('_',HeaderNo.No_)>0 then
CAST(SUBSTRING(HeaderNo.No_, 6, len(CHARINDEX('_',HeaderNo.No_))) AS INT)else 0 end)
--MAX(case when CHARINDEX('_',NavBomHeader.No_)>0 then CAST(SUBSTRING(HeaderNo.No_,CHARINDEX('_',HeaderNo.No_)+1,len(CHARINDEX('_',HeaderNo.No_))) AS INT) else 0 end)+1
from nameoftable as HeaderNo
where SUBSTRING(HeaderNo.No_, 1, case when CHARINDEX('_',HeaderNo.No_)>0 then CHARINDEX('_',HeaderNo.No_)-1 else len(HeaderNo.No_) end) ='M308'
Another implementation.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, No_ VARCHAR(30));
INSERT INTO #tbl (No_) VALUES
('M308_7'),
('M308_8'),
('M308_9'),
('M308_10');
-- DDL and sample data population, end
SELECT NextNo = MAX(TRY_CAST(RIGHT(No_, LEN(No_) - pos) AS INT)) + 1
FROM #tbl
CROSS APPLY (SELECT CHARINDEX('_', No_)) AS t(pos);
Output
+--------+
| NextNo |
+--------+
| 11 |
+--------+
You probably have a design flaw in your database. I suspect that you should be using an identity column.
In any case, the answer to your question is logic like this:
select concat('M308_', max(try_convert(int, stuff(no_, 1, charindex('_', no_), ''))) + 1)
from (values ('M308_7'), ('M308_8'), ('M308_9'), ('M308_10')) v(no_);
Here is a db<>fiddle.

T-SQL: Efficient way to add up column values

Now I'm sure this has been asked and superbly been answered on here. However, I am unable to find the answer since it touches many keywords.
I basically want to replace a table of the form:
Type amount param note
7 2 str1 NULL
42 12 str2 NULL
128 7 str3 samplenote
42 12 NULL NULL
101 4 str4 NULL
42 12 NULL NULL
7 1 str1 samplenote
128 2 str5 NULL
with a table like:
Type amount param note
7 3 str1 combined
42 36 NULL combined
128 9 NULL combined
101 4 str4 combined
In words, I seek to sum up the amount parameter based on its type while declaring param = NULL for all "unclear" fields. (param should be NULL when the param values of combined Types have more than one different content; else, param should have the original content.)
With my python background, I tackled this task with a for loop approach, iterating through the types, adding a new row for every type with summed up amount and note = 'combined', to then delete the remaining rows (see below). There has to be a more efficient way with some JOIN statement I'm sure. But how would that look like?
FYI, this is the solution I am working on (not functioning yet!):
/*** dbo.sourcetable holds all possible Type values ***/
CREATE PROCEDURE [sumup]
AS
BEGIN
DECLARE #i int = (SELECT TOP (1) Type FROM [dbo].[sourcetable] ORDER BY Type)
DECLARE #MaxType int = (SELECT TOP (1) Type FROM [dbo].[sourcetable] ORDER BY Type DESC)
DECLARE #sum int
BEGIN TRY
WHILE #i <= #MaxType
BEGIN
IF EXISTS (SELECT * FROM [dbo].[worktable] WHERE Type = #i)
BEGIN
SET #sum = (SELECT SUM(amount) FROM [dbo].[worktable] WHERE Type = #i)
BEGIN
WITH cte AS (SELECT * FROM [dbo].[worktable] WHERE Type = #i)
INSERT INTO [dbo].[worktable]
([Type]
,[amount]
,[param]
,[note]
SELECT
cte.Type
,#sum
,cte.param
,'combined'
FROM cte
END
DELETE FROM [dbo].[worktable] WHERE Type = #i AND ISNULL([note],'') <> 'combined'
END
SET #i = #i + 1
END
END TRY
BEGIN CATCH
-- some errorlogging code
END CATCH
END
GO
This can be achieved with a single select statement.
If you require your combined flag to only apply to where more than one row has been combined, add another case expression checking the result of either a count(1) for rows combined or count(distinct param) for unique param values combined:
declare #t as table(type int, amount int, param varchar(15), note varchar(15));
insert into #t values (7,2,'str1',NULL),(42,12,'str2',NULL),(128,7,'str3','samplenote'),(42,12,NULL,NULL),(101,4,'str4',NULL),(42,12,NULL,NULL),(7,1,'str1','samplenote'),(128,2,'str5',NULL);
select type
,sum(amount) as amount
,case when count(distinct isnull(param,'')) = 1
then max(param)
else null
end as param
,'combined' as note
from #t
group by type
order by type;
Output:
+------+--------+-------+----------+
| type | amount | param | note |
+------+--------+-------+----------+
| 7 | 3 | str1 | combined |
| 42 | 36 | NULL | combined |
| 101 | 4 | str4 | combined |
| 128 | 9 | NULL | combined |
+------+--------+-------+----------+
I am doing this way from keyboard, but this may work or be close to what you want
Select type , amount , iif( dc=1,p,null) param, 'combined' note
from
(
Select type, sum(amount) amount,
count(distinct Param) dc,max(Param) p
From ....
Group by type
) x
Here is a possible solution:
declare #tbl as table (
type int
,amount int
,param varchar(15)
,note varchar(15)
)
insert into #tbl values (7,2,'str1',NULL)
insert into #tbl values (42,12,'str2',NULL)
insert into #tbl values (128,7,'str3','samplenote')
insert into #tbl values (42,12,NULL,NULL)
insert into #tbl values (101,4,'str4',NULL)
insert into #tbl values (42,12,NULL,NULL)
insert into #tbl values (7,1,'str1','samplenote')
insert into #tbl values (128,2,'str5',NULL)
;WITH CTE AS (
SELECT
type
,SUM(AMOUNT) AS amount
,COUNT(DISTINCT ISNULL(param, 'dummy value')) AS ParamNo
,MAX(Param) AS Param
FROM #tbl
GROUP BY type
) SELECT
type
,amount
,CASE WHEN ParamNo = 1 THEN Param ELSE NULL END AS Param
,'combined' AS note
FROM CTE
This should work:
Select Type, sum(amount) as amount, count(distinct param)
, case when count(distinct param) = 1 then max(param) end as param,
'Combined' as note
From
mytable
Group By Type

Convert INT column values to an empty string using ISNULL

I need to convert column ID of INT data type to a empty string ['']. I should not modify the source column data type, but need to convert it in my transformation in the other table. The ID column is "nullable" as it has null in it.This is my code.
CREATE TABLE #V(ID INT) ;
INSERT INTO #V
VALUES (1),(2),(3),(4),(5),(NULL),(NULL) ;
SELECT CASE WHEN CAST(ISNULL(ID,'') AS VARCHAR(10)) = '' THEN '' ELSE ID END AS ID_Column
FROM #V;
this returns:
ID_Column
1
2
3
4
5
NULL
NULL
when I modify my CASE statement it as follows:
CASE WHEN CAST(ISNULL(ID,'') AS VARCHAR(10)) = '' THEN '' ELSE ID END AS ID_Column
it returns:
ID_Column
1
2
3
4
5
0
0
Is this what you want?
select coalesce(cast(id as varchar(255)), '')
from #v;
You have to turn the entire result column into a single column. If you want a blank value, then the type is some sort of character string.
In your examples, the else id means that the result from the case is an integer, which is why you are getting either 0 or NULL.

Take a value from an SQL table cell and insert it in another cell

I have an old SQL database (Microsoft's SQL Server) with thousands of rows that contains data as follows:
ID urlString
1 page.aspx?pageID=34
2 page.aspx?pageID=163
3 page.aspx
4 page.aspx?pageID=23
I've added a new column (pageID) to the database. I want to create an UPDATE query to copy the pageID from the URLstring and insert it in the new column (pageID) as follows. If there is no pageID I want to add 0. How can I accomplish that?
ID URLstring pageID
1 page.aspx?pageID=34 34
2 page.aspx?pageID=163 163
3 page.aspx 0
4 page.aspx?pageID=23 23
UPDATE YourTable
SET pageID=
SUBSTRING(urlString,CHARINDEX('=', urlString)+1,CHARINDEX('=', urlString))
To have the 0 value
UPDATE YourTable
SET pageID=
CASE
WHEN CHARINDEX('=', urlString) > 0 THEN
SUBSTRING(urlString,CHARINDEX('=', urlString)+1,CHARINDEX('=', urlString))
ELSE 0
END
please try the following
SELECT urlString, cast(REVERSE(SUBSTRING(REVERSE(urlString),0,CHARINDEX('=',REVERSE(urlString)))) as smallint) AS [pageID]
Hope this helps.
Well, whichever SQL language variant the database uses will make a difference here. (i.e. SQLplus, NOSQL, etc.) However, it shouldn't be toooooooooo complicated. Assuming that both columns are INTs, you could probably just do something like so
UPDATE table_name
SET pageID = URLstring;
Here is some other sources for additional information.
A similar stack overflow question:
Copy data from one column to other column (which is in a different table)
This is a TutorialsPoint webpage on the matter: http://www.tutorialspoint.com/sql/sql-update-query.htm (TutorialsPoint is usually one of my first stops for any programming-related knowledge, it's quite a valuable website.)
This is a w3schools webpage on the matter: http://www.w3schools.com/sql/sql_update.asp
Hope you get everything figured out!
You can achieve this by the PARSENAME using the following UPDATE query:
UPDATE TestTable
SET pageID = CASE WHEN ISNUMERIC(PARSENAME(REPLACE(URLstring, '=', '.'), 1)) = 1 THEN PARSENAME(REPLACE(URLstring, '=', '.'), 1)
ELSE 0 END
Sample execution with the given sample data
DECLARE #TestTable TABLE (ID INT, URLstring VARCHAR (200), PageID INT);
INSERT INTO #TestTable (ID, URLstring, pageID) VALUES
(1, 'page.aspx?pageID=34' , NULL ),
(2, 'page.aspx?pageID=163' , NULL ),
(3, 'page.aspx' , NULL ),
(4, 'page.aspx?pageID=23' , NULL );
UPDATE #TestTable
SET pageID = CASE WHEN ISNUMERIC(PARSENAME(REPLACE(URLstring, '=', '.'), 1)) = 1 THEN PARSENAME(REPLACE(URLstring, '=', '.'), 1)
ELSE 0 END
So the SELECT * FROM #TestTable will result as:
ID URLstring PageID
------------------------------------
1 page.aspx?pageID=34 34
2 page.aspx?pageID=163 163
3 page.aspx 0
4 page.aspx?pageID=23 23
I try it:
update yourtable
set pageID=
case when
substring(URLstring, charindex('=', URLstring) +1, len(URLstring) - charindex('=', URLstring) )
=URLstring then '0'
else
substring(URLstring, charindex('=', URLstring) +1, len(URLstring) - charindex('=', URLstring) )
end
Using CASE, PATINDEX and SUBSTRING it's fairly easy to extract the page id from the url.
Create and populate sample table (Please save us this step in your future questions)
DECLARE #T As TABLE
(
Id int IDENTITY(1,1),
URLString varchar (40),
PageId int
)
INSERT INTO #T (URLString) VALUES
('page.aspx?blabla=yadayada&pageID=34'),
('page.aspx?pageID=163'),
('page.aspx'),
('page.aspx?pageID=23')
Update statement:
UPDATE #T
SET PageId = CAST(
CASE WHEN PATINDEX('%pageID=%', URLString) > 0 THEN
SUBSTRING(URLString, PATINDEX('%pageID=%', URLString) + 7, LEN(URLString))
ELSE
'0'
END
As int)
Verification:
SELECT Id, URLString, PageId
FROM #T
Results:
Id URLString PageId
----------- ---------------------------------------- -----------
1 page.aspx?blabla=yadayada&pageID=34 34
2 page.aspx?pageID=163 163
3 page.aspx 0
4 page.aspx?pageID=23 23