SQL query: create category column based on a varchar column in table containing specific values - sql

I have a table similar to the following:
Date Description Value1 Value2
01/01/2012 shiny colour 2 0
01/01/2012 yellow colour 2 2
03/01/2012 matt colour 2 2
03/01/2012 matt 4 1
03/01/2012 shiny 2 2
I want to write a SELECT SQL query (T-SQL) that will output all of the above columns but also display an extra column as the output of the SELECT statement whose value depends on the presence of the word "colour" in the Description (if "colour" is present it would be one value, if not it would show a different value).
(I would also want to display another extra column on top of that whose value depends on the presence of the words "matt" or "shiny" in the Description column. But I assume the method of doing this would be similar).
I believe I should be able to do this using the COALESCE function but I'm not familiar with this and am struggling to get anything working?
EXTENSION
Hey, thanks for your answers. They're really helpful. I have one more extension to the question. My second generated column relies on info in the first generated column. So something like:
SELECT *,
CASE
WHEN Description LIKE '%colour%' THEN 'SomeValue'
ELSE 'Unclassified'
END AS Category1,
CASE
WHEN AnotherColumn LIKE 'Something' THEN 'SomeValue'
WHEN Category1='Unclassified' THEN 'Unclassified'
ELSE 'Generic'
END AS Category2
FROM table_name
How do I get the output of Category2 to rely on output of Category1? I'm trying something like the above but it's not working.
My extension question was answered here: T-SQL CASE statement relies on another CASE statement in same SELECT query

SELECT *,
CASE WHEN Description LIKE '%colour%' THEN
1
ELSE
0
END AS HasColour,
CASE WHEN Description LIKE '%matt%' THEN
1
ELSE
0
END AS HasMatt,
CASE WHEN Description LIKE '%shiny%' THEN
1
ELSE
0
END AS HasShiny
FROM table_name
You would just add more columns for all the different words that you want to search for. Obviously you can change the return type of the columns to whatever you want, but I thought a boolean would be suitable in this situation.

Unless I misunderstand what you are asking, you could use a case statement:
SELECT Date,
Description,
Value1,
Value2,
Case when Description like '%colour%' then OTHERCOL else OTHERCOL2 end as Colourful,
Case when Description like '%matt%' then OTHERCOL else OTHERCOL2 end as Matt,
Case when Description like '%shiny%' then OTHERCOL else OTHERCOL2 end as Shiny,
FROM yourTable

Related

New column based on list of values SQL

I am new to SQL and working on a database that needs a binary indicator based on the presence of string values in a column. I'm trying to make a new table as follows:
Original:
Indicator
a, b, c
c, d, e
Desired:
Indicator
type
a, b, c
1
c, d, e
0
SQL code:
SELECT
ID,
Contract,
Indicator,
CASE
WHEN Indicator IN ('a', 'b')
THEN 1
ELSE 0
END as Type
INTO new_table
FROM old_table
The table I keep creating reports every type as 0.
I also have 200+ distinct indicators, so it will be really time-consuming to write each as:
CASE
WHEN Indicator = 'a' THEN '1'
WHEN Indicator = 'b' THEN '1'
Is there a more streamlined way to think about this?
Thanks!
I think the first step is to understand why your code doesn’t work right now.
If your examples of what’s Indicator column are literally the strings you noted (a, b, c in one string and c, d, e in another) you should understand that your case statement is saying “I am looking for an exact match on the full value of Indicator against the following list -
The letter A or
The letter B
Essentially- you are saying “hey SQL, does ‘a,b,c’ match to ‘a’? Or does ‘a,b,c’ match to ‘b’. ?”
Obviously SQL’s answer is “these don’t match” which is why you get all 0s.
You can try wildcard matching with the LIKE syntax.
Case when Indicator like ‘%a%’ or Indicator like ‘%b%’ then 1 else 0 end as Type
Now, if the abc and cde strings aren’t REALLY what’s in your database then this approach may not work well for you.
Example, let’s say your real values are words that are all slapped together in a single string.
Let’s say that your strings are 3 words each.
Cat, Dog, Man
Catalog, Stick, Shoe
Hair, Hellcat, Belt
And let’s say that Cat is a value that should cause Type to be 1.
If you write: case when Indicator like ‘%cat%’ then 1 else 0 end as Type - all 3 rows will get a 1 because the wildcard will match Cat in Catalog and cat in Hellcat.
I think the bottom line is that unless your Indicator values really are 3 letters and your match criteria is a single letter, you very well could be better off writing a 200 line long case statement if you need this done any time soon.
A better approach to consider (depending on things like are you going to have 300 different combinations a week or month or year from now?)
If yes, wouldn’t it be nice if you had a table with a total of 6 rows - like so?
Indicator | Indictor_Parsed
a,b,c | a
a,b,c | b
a,b,c | c
c,d,e | c
c,d,e | d
c,d,e | e
Then you could write the query as you have it case when Indicator_Parsed in (‘a’, ‘b’) then 1 else 0 end as Type - as a piece of a more verbose solution.
If this approach seems useful to you, here’s a link to the page that lets you parse those comma-separated-values into additional rows. Turning a Comma Separated string into individual rows
ON mysql/sql server You can do it as follows :
insert into table2
select Indicator,
CASE WHEN Indicator like '%a%' or Indicator like '%b%' THEN 1 ELSE 0 END As type
from table1;
demo here
You can use the REGEXP operator to check for presence of either a, b or both.
SELECT Indicator,
Indicator REGEXP '.*[ab].*'
FROM tab
If you need that into a table, you either create it from scratch
CREATE your_table AS
SELECT Indicator,
Indicator REGEXP '.*[ab].*'
FROM tab
or you insert values in it:
INSERT INTO your_table
SELECT Indicator,
Indicator REGEXP '.*[ab].*'
FROM tab
Check the demo here.

Oracle SQL - Multiple return from case

I may be trying it wrong. I am looking for any approach which is best.
Requirement:
My Query joins 4-5 tables based on few fields.
I have a column called product id. In my table there are 1.5 million rows. Out of those only 10% rows has product ids with the following attribute
A300X-%
A500Y-%
300,500, 700 are valid model numbers. X and Y are classifications. My query picks all the systems.
I have a check as follows
CASE
WHEN PID LIKE 'A300X%'
THEN 'A300'
...
END AS MODEL
Similarly
CASE
WHEN PID LIKE 'A300X%'
THEN 'X'
...
END AS GENRE
I am looking for the best option from the below
How do I Combine both case statement and add another[third] case which will have these two cases. i.e
CASE
WHEN desc in ('AAA')
First Case
Second Case
ELSE
don't do anything for other systems
END
Is there any regex way of doing this? Before first - take the string. Look for X, Y and also 300,500,700.
Is there any other way of doing this? Or doing via code is the best way?
Any suggestions?
EDIT:
Sample desc:
AAA,
SoftwARE,
sw-app
My query picks all the desc. But the case should be running for AAA alone.
And Valid models are
A300X-2x-P
A500Y-5x-p
A700X-2x-p
A50CE-2x-P
I have to consider only 300,500,700. And the above two cases.
Expected result:
MODEL GENRE
A300 X
A500 Y
A300 Y
Q: How do I Combine both CASE statement expressions
Each CASE expression will return a single value. If the requirement is to return two separate columns in the resultset, that will require two separate expressions in the SELECT list.
For example:
DESC PID model_number genre
---- ---------- ------------ ------
AAA A300X-2x-P 300 X
AAA A500Y-5x-p 500 Y
AAA A700X-2x-p 700 X
AAA A50CE-2x-P (NULL) (NULL)
FOO A300X-2x-P (NULL) (NULL)
There will need to be an expression to return the model_number column, and a separate expression to return the genre column.
It's not possible for a single expression to return two separate columns.
Q: and add another[third] case which will have these two cases.
A CASE expression returns a value; we can use a CASE expression almost anywhere in a SQL statement where we can use a value, including within another CASE expression.
We can also combine multiple conditions in a WHEN test with AND and OR
As an example of combining conditions and nesting CASE expressions ditions...
CASE
WHEN ( ( t.PID LIKE '_300%' OR t.PID LIKE '_500%' OR t.PID LIKE '_700%' )
AND ( t.DESC = 'AAA' )
)
THEN CASE
WHEN ( t.PID LIKE '____X%' )
THEN 'X'
WHEN ( t.PID LIKE '____Y%' )
THEN 'Y'
ELSE NULL
END
ELSE NULL
END AS `genre`
There are other expressions that will return an equivalent result; the example shown here isn't necessarily the best expression. It just serves as a demonstration of combining conditions and nesting CASE expressions.
Note that to return another column model we would need to include another expression in the SELECT list. Similar conditions will need to be repeated; it's not possible to reference the WHEN conditions in another CASE expression.
Based on your sample data, logic such as this would work:
(CASE WHEN REGEXP_LIKE(PID, '^A[0-9]{3}[A-Z]-')
THEN SUBSTR(PID, 1, 4)
ELSE PID
END) AS MODEL
(CASE WHEN REGEXP_LIKE(PID, '^A[0-9]{3}[A-Z]-')
THEN SUBSTR(PID, 5, 1)
ELSE PID
END) AS GENRE
This assumes that the "model number" always starts with "A" and is followed by three digits (as in your example data). If the model number is more complicated, you may need regexp_substr() to extract the values you want.

SQL Server- CASE WHEN THEN in list- multiple values

I know that SQL CASE will not accept in list for the then part of the CASE statement.
What I am ideally looking for is such a case:
CASE WHEN 'A' Then in list ['B' , 'C'] ELSE 'A' END
or
CASE WHEN 'A' Then 'B' or 'C' ELSE 'A' END
I am using this CASE Statement as a part of Designing a SQL view.
Just to let you know, I have already checked Multiple values in SQL CASE's THEN Statement and the answer there didn't work for me.
EDIT, PROBLEM Description and Dummy Data:
My main table is dbo.main
In this table I have data in form
Year CTG
2015 A
2015 B
2015 C
2015 D
In my design view I worte this:
SELECT DISTINCT YEAR, 'GENRL' AS SETID, '000001' AS LABOR_AGREEMENT, CTG
FROM dbo.main
Now my ultimate goal is to have below table:
Year CTG
2015 B/C
2015 B
2015 C
2015 D
The CTG value is a key to initiate another table in another page, and I want that table to show all the values for CTG: B and CTG:C
You can use a searched CASE:
SELECT (CASE WHEN CTG = 'A' THEN 'B/C'
ELSE CTG
END)
FROM dbo.main
Actually, this works with a simple CASE as well:
SELECT (CASE CTG WHEN 'A' THEN 'B/C'
ELSE CTG
END)
FROM dbo.main
There is no "or" posibility for a single field in a single row. A single colunm (field) can contain one value in a single row. What you ask for, sounds like can be solved with a second column with the extra value (when the case aplies, or null), or instead (but not addressed in your question) an extra row with the extra value on it.
As you comment that you want "values" but not concatenation (or something else), you can generate the extra column to fit the second value when it applies like this:
SELECT DISTINCT YEAR, 'GENRL' AS SETID, '000001' AS LABOR_AGREEMENT,
CASE WHEN CTG='A' THEN 'B' ELSE CTG END AS CTG,
CASE WHEN CTG='A' THEN 'C' END AS CTGbis -- else null is the default behavior
FROM dbo.main

Transform Numbers to Text

A field in my cube contains numerical values which I would like transformed and displayed as text.
For example
1 is a sale
2 is a return
etc
Is a named caculation best?
Easiest way to do this would be with a case statement,
SELECT
CASE someValue
WHEN 1 THEN 'sale'
WHEN 2 THEN 'return'
END
FROM MyTable ;

SQL (SQLite) count for null-fields over all columns

I've got a table called datapoints with about 150 columns and 2600 rows. I know, 150 columns is too much, but I got this db after importing a csv and it is not possible to shrink the number of columns.
I have to get some statistical stuff out of the data. E.g. one question would be:
Give me the total number of fields (of all columns), which are null. Does somebody have any idea how I can do this efficiently?
For one column it isn't a problem:
SELECT count(*) FROM datapoints tb1 where 'tb1'.'column1' is null;
But how can I solve this for all columns together, without doing it by hand for every column?
Best,
Michael
Building on Lamak's idea, how about this idea:
SELECT (N * COUNT(*)) - (
COUNT(COLUMN_1)
+ COUNT(COLUMN_2)
+ ...
+ COUNT(COLUMN_N)
)
FROM DATAPOINTS;
where N is the number of columns. The trick will be in making the summation series of COUNT(column), but that shouldn't be too terrible with a good text editor and/or spreadsheet.
i don't think there is an easy way to do it. i'd get started on the 150 queries. you only have to replace one word (column name) each time.
Well, COUNT (and most aggregations funcions) ignore NULL values. In your case, since you are using COUNT(*), it counts every row in the table, but you can do that on any column. Something like this:
SELECT TotalRows-Column1NotNullCount, etc
FROM (
SELECT COUNT(1) TotalRows,
COUNT(column1) Column1NotNullCount,
COUNT(column2) Column2NotNullCount,
COUNT(column3) Column3NotNullCount ....
FROM datapoints) A
To get started it's often helpful to use a visual query tool to generate a field list and then use cut/paste/search/replace or manipulation in a spreadsheet program to transform it into what is needed. To do it all in one step you can use something like:
SELECT SUM(CASE COLUMN1 WHEN NULL THEN 1 ELSE 0 END) +
SUM(CASE COLUMN2 WHEN NULL THEN 1 ELSE 0 END) +
SUM(CASE COLUMN3 WHEN NULL THEN 1 ELSE 0 END) +
...
FROM DATAPOINTS;
With a visual query builder you can quickly generate:
SELECT COLUMN1, COLUMN2, COLUMN3 ... FROM DATAPOINTS;
You can then replace the comma with all the text that needs to appear between two field names followed by fixing up the first and last fields. So in the example search for "," and replace with " WHEN NULL 1 ELSE 0 END) + SUM(CASE " and then fix up the first and last fields.