SQL computed column based on a special character on another column - sql

I am not good with SQL at all, barely have an idea on how to do basic scripts suck as delete, drop, add.
I have this data with about 12 columns, I want to add a calculated column which will change depending if a special character shows up in another column.
lets say
A C
Money$ YES
Money NO
that is the idea, I want to create a column C where it says yes if there is a $ sign on the column A. Is this possible? I am assuming you can use something similar to an if condition but I have no experience with SQL scripting.

You would use a case expression and like:
select t.*,
(case when a like '%$%' then 'YES' else 'NO' end) as c
from t;
The following is just commentary.
This is very basic syntax for SQL. I would recommend that you spend some time to learn the basics. Learning-as-you-go is an okay approach -- assuming you have some fundamentals to build on. Otherwise, you are likely to spend a lot of time to learn a few things, and you may not learn the best way to do things.

yes, this is possible. you'll have to replace the parts in braces ({}) with the appropriate object names. I also use a bit rather than 'Yes'/'No'; as that seems better suited:
ALTER TABLE {YourTable} ADD {New Column Name} AS CONVERT(bit, CASE WHEN {Column} LIKE '%$%' THEN 1 ELSE 0 END) PERSISTED;
Note that this will return 0 if the column ({Column}) has a value of NULL, not NULL; unsure if this is the correct logic however, this should be more than enough to get the ball rolling. If not, read up on the CASE expression and NULL logic.

Regexp match can help you find out if there is a character you consider as special char in the strings:
SELECT
ColumnA
, SUBSTRING(ColumnA, PATINDEX('%[^ a-zA-Z0-9]%', ColumnA), 1) AS FirstSpecialChar
WHERE
ColumnA LIKE '%[^ a-zA-Z0-9]%'
;
The pattern [^ a-zA-Z0-9] will match on any character which is not a number, a space or an alphabetic character (note the ^ at the beginning of the character group - that mean NOT)

You can use regex to check any special character in column EX:
SQL SERVER
SELECT CASE WHEN 'ABCD$' Like '%[^a-zA-Z0-9]%' 1 THEN 'YES' ELSE 'NO' END as result
MYSQL
SELECT CASE WHEN 'ABCD$' REGEXP '[^a-zA-Z0-9]' = 1 THEN 'YES' ELSE 'NO' END as result
Regex can be changed as per the requirement
REGEXP '[^[:alnum:]]'

Related

SQL - Unable to find partially matching data in two columns

I've never posted before, I've usually been able to find my answer, so please bear with me if I exclude anything or format incorrectly. Here is my issue:
I have two columns that include similar data, for example:
Column1 Column2
BASKETBALL BasketBall-CAVS
BASEBALL REDS Baseball-SPORTS
I am not searching for a specific word, just any word that is found in both columns should populate a "no" under a third column. So both of the above records should return a NO. I attempted this:
CASE
WHEN Column1 NOT LIKE
CONCAT('%',Column2,'%') THEN 'Yes'
ELSE 'No'
END AS Needs_Updated;
For some reason, only the first record pictured above returns a "No" in the "Needs_Updated" column. The second record returns a "Yes" (which isn't correct, two words match in that column). The only difference in the second record is there is multiple words in column 1. Can anyone help me out? Thanks in advance!
I think you can do what you want with regular expressions. Not all databases support them, so this is tricky with those databases.
Using MySQL syntax:
select t.*,
(case when column2 regexp replace(column1, ' ', '|') then 'no' else 'yes' end) as needs_updated
from t;
Have you tried Charindex
SELECT CASE WHEN CHARINDEX(Column2,Column1) > 0 ) THEN 'NO' ELSE 'YES' AS Needs_Updated
CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ])
start_location is optional
https://learn.microsoft.com/en-us/sql/t-sql/functions/charindex-transact-sql

SQL - Conditionally joining two columns in same table into one

I am working with a table that contains two versions of stored information. To simplify it, one column contains the old description of a file run while another column contains the updated standard for displaying ran files. It gets more complicated in that the older column can have multiple standards within itself. The table:
Old Column New Column
Desc: LGX/101/rpt null
null Home
Print: LGX/234/rpt null
null Print
null Page
I need to combine the two columns into one, but I also need to delete the "Print: " and "Desc: " string from the beginning of the old column values. Any suggestions? Let me know if/when I'm forgetting something you need to know!
(I am writing in Cache SQL, but I'd just like a general approach to my problem, I can figure out the specifics past that.)
EDIT: the condition is that if substr(oldcol,1,5) = 'desc: ' then substr(oldcol,6)
else if substr(oldcol,1,6) = 'print: ' then substr(oldcol,7) etc. So as to take out the "desc: " and the "print: " to sanitize the data somewhat.
EDIT2: I want to make the table look like this:
Col
LGX/101/rpt
Home
LGX/234/rpt
Print
Page
It's difficult to understand what you are looking for exactly. Does the above represent before/after, or both columns that need combining/merging.
My guess is that COALESCE might be able to help you. It takes a bunch of parameters and returns the first non NULL.
It looks like you're wanting to grab values from new if old is NULL and old if new is null. To do that you can use a case statement in your SQL. I know CASE statements are supported by MySQL, I'm not sure if they'll help you here.
SELECT (CASE WHEN old_col IS NULL THEN new_col ELSE old_col END) as val FROM table_name
This will grab new_col if old_col is NULL, otherwise it will grab old_col.
You can remove the Print: and Desc: by using a combination of CharIndex and Substring functions. Here it goes
SELECT CASE WHEN CHARINDEX(':',COALESCE(OldCol,NewCol)) > 0 THEN
SUBSTRING(COALESCE(OldCol,NewCol),CHARINDEX(':',COALESCE(OldCol,NewCol))+1,8000)
ELSE
COALESCE(OldCol,NewCol)
END AS Newcolvalue
FROM [SchemaName].[TableName]
The Charindex gives the position of the character/string you are searching for.
So you get the position of ":" in the computed column(Coalesce part) and pass that value to the substring function. Then add +1 to the position which indicates the substring function to get the part after the ":". Now you have a string without "Desc:" and "Print:".
Hope this helps.

How do I sort a VARCHAR column in PostgreSQL that contains words and numbers?

I need to order a select query using a varchar column, using numerical and text order. The query will be done in a java program, using jdbc over postgresql.
If I use ORDER BY in the select clause I obtain:
1
11
2
abc
However, I need to obtain:
1
2
11
abc
The problem is that the column can also contain text.
This question is similar (but targeted for SQL Server):
How do I sort a VARCHAR column in SQL server that contains words and numbers?
However, the solution proposed did not work with PostgreSQL.
Thanks in advance, regards,
I had the same problem and the following code solves it:
SELECT ...
FROM table
order by
CASE WHEN column < 'A'
THEN lpad(column, size, '0')
ELSE column
END;
The size var is the length of the varchar column, e.g 255 for varying(255).
You can use regular expression to do this kind of thing:
select THECOL from ...
order by
case
when substring(THECOL from '^\d+$') is null then 9999
else cast(THECOL as integer)
end,
THECOL
First you use regular expression to detect whether the content of the column is a number or not. In this case I use '^\d+$' but you can modify it to suit the situation.
If the regexp doesn't match, return a big number so this row will fall to the bottom of the order.
If the regexp matches, convert the string to number and then sort on that.
After this, sort regularly with the column.
I'm not aware of any database having a "natural sort", like some know to exist in PHP. All I've found is various functions:
Natural order sort in Postgres
Comment in the PostgreSQL ORDER BY documentation

What does this SQL Query mean?

I have the following SQL query:
select AuditStatusId
from dbo.ABC_AuditStatus
where coalesce(AuditFrequency, 0) <> 0
I'm struggling a bit to understand it. It looks pretty simple, and I know what the coalesce operator does (more or less), but dont' seem to get the MEANING.
Without knowing anymore information except the query above, what do you think it means?
select AuditStatusId
from dbo.ABC_AuditStatus
where AuditFrequency <> 0 and AuditFrequency is not null
Note that the use of Coalesce means that it will not be possible to use an index properly to satisfy this query.
COALESCE is the ANSI standard function to deal with NULL values, by returning the first non-NULL value based on the comma delimited list. This:
WHERE COALESCE(AuditFrequency, 0) != 0
..means that if the AuditFrequency column is NULL, convert the value to be zero instead. Otherwise, the AuditFrequency value is returned.
Since the comparison is to not return rows where the AuditFrequency column value is zero, rows where AuditFrequency is NULL will also be ignored by the query.
It looks like it's designed to detect a null AuditFrequency as zero and thus hide those rows.
From what I can see, it checks for fields that aren't 0 or null.
I think it is more accurately described by this:
select AuditStatusId
from dbo.ABC_AuditStatus
where (AuditFrequency IS NOT NULL AND AuditFrequency != 0) OR 0 != 0
I'll admit the last part will never do anything and maybe i'm just being pedantic but to me this more accurately describes your query.
The idea is that it is desireable to express a single search condition using a single expression but it's merely style, a question of taste:
One expression:
WHERE age = COALESCE(#parameter_value, age);
Two expressions:
WHERE (
age = #parameter_value
OR
#parameter_value IS NULL
);
Here's another example:
One expression:
WHERE age BETWEEN 18 AND 65;
Two expressions
WHERE (
age >= 18
AND
age <= 65
);
Personally, I have a strong personal perference for single expressions and find them easier to read... if I am familiar with the pattern used ;) Whether they perform differently is another matter...

What is the best way to select string fields based on character ranges?

I need to add the ability for users of my software to select records by character ranges.
How can I write a query that returns all widgets from a table whose name falls in the range Ba-Bi for example?
Currently I'm using greater than and less than operators, so the above example would become:
select * from widget
where name >= 'ba' and name < 'bj'
Notice how I have "incremented" the last character of the upper bound from i to j so that "bike" would not be left out.
Is there a generic way to find the next character after a given character based on the field's collation or would it be safer to create a second condition?
select * from widget
where name >= 'ba'
and (name < 'bi' or name like 'bi%')
My application needs to support localization. How sensitive is this kind of query to different character sets?
I also need to support both MSSQL and Oracle. What are my options for ensuring that character casing is ignored no matter what language appears in the data?
Let's skip directly to localization. Would you say "aa" >= "ba" ? Probably not, but that is where it sorts in Sweden. Also, you simply can't assume that you can ignore casing in any language. Casing is explicitly language-dependent, with the most common example being Turkish: uppercase i is İ. Lowercase I is ı.
Now, your SQL DB defines the result of <, == etc by a "collation order". This is definitely language specific. So, you should explicitly control this, for every query. A Turkish collation order will put those i's where they belong (in Turkish). You can't rely on the default collation.
As for the "increment part", don't bother. Stick to >= and <=.
For MSSQL see this thread: http://bytes.com/forum/thread483570.html .
For Oracle, it depends on your Oracle version, as Oracle 10 now supports regex(p) like queries: http://www.psoug.org/reference/regexp.html (search for regexp_like ) and see this article: http://www.oracle.com/technology/oramag/webcolumns/2003/techarticles/rischert_regexp_pt1.html
HTH
Frustratingly, the Oracle substring function is SUBSTR(), whilst it SQL-Server it's SUBSTRING().
You could write a simple wrapper around one or both of them so that they share the same function name + prototype.
Then you can just use
MY_SUBSTRING(name, 2) >= 'ba' AND MY_SUBSTRING(name, 2) <= 'bi'
or similar.
You could use this...
select * from widget
where name Like 'b[a-i]%'
This will match any row where the name starts with b, the second character is in the range a to i, and any other characters follow.
I think that I'd go with something simple like appending a high-sorting string to the end of the upper bound. Something like:
select * from widgetwhere name >= 'ba' and name <= 'bi'||'~'
I'm not sure that would survive EBCDIC conversion though
You could also do it like this:
select * from widget
where left(name, 2) between 'ba' and 'bi'
If your criteria length changes (as you seemed to indicate in a comment you left), the query would need to have the length as an input also:
declare #CriteriaLength int
set #CriteriaLength = 4
select * from widget
where left(name, #CriteriaLength) between 'baaa' and 'bike'