SQL CASE How do I correct assign a value? - sql

First, I would like to say I have already spent the due time and diligence on my part by watching videos, using other sources, and reading other posts and answers on SOF before asking this and have been unable to find a solution.
The issue I am running into, in a particular case, is a certain type is being passed in, which would require the use of LIKE as the specific type itself will not match anything as three types use the one type, say 'painting' in this situation. The database has a 'painting small' and 'painting large.'
Code
// I tried this
CASE WHEN type = 'painting' THEN inventory.type LIKE '%'+type+'%' ELSE inventory.type = type END
I keep running into the "An expression of a non-boolean type specified in a context where a condition is expected. There are a few other variations I have tried as well as IF ELSE, however, I run into the same issue. Someone else may be able to word this question better.
I mainly want to be pointed in the right direction and receive clarification on what I am doing wrong.
Thank you

There are a few problems with your query. Rather than the CASE expression itself I'm going to address the less obvious problem, your lack of prefixing. Take this clause:
inventory.type LIKE '%'+type+'%'
This could likely either error, due to an ambiguous column name, or resolve to inventory.type LIKE '%'+inventory.type+'%'; obviously the latter is going to always be true unless the column type has the value NULL. Always prefix your column names, especially when your query contains 2+ tables.
As for the actual problem, this is presumably part of a WHERE, therefore use OR and AND logic:
WHERE (({Other Table Prefix}.[type] = 'painting' AND inventory.[type] LIKE '%' + {Other Table Prefix}.[Type] + '%')
OR ({Other Table Prefix}.[type] != 'painting' AND inventory.[type] = {Other Table Prefix}.[Type]))
Obviously, you need to appropriately replace {Other Table Prefix} with the correct prefix.

The problem seems to be in the
LIKE '%'+type+'%'
where LIKE may be returning a boolean value.

Related

SQL column name with function

I want to create 3 new columns with their names reffering to some date varibales and this is not possible to write them like this. So the first column name should be YEAR2022, 2nd column YEAR2021 and 3rd column YEAR2020.
Can you please give me an idea how to write this?
select column1*2 as CONCAT('YEAR',YEAR(DATEADD(YY,0,GETDATE()))),
column1*3 as CONCAT('YEAR',YEAR(DATEADD(YY,-1,GETDATE()))),
column1*4 as CONCAT('YEAR',YEAR(DATEADD(YY,-2,GETDATE()))) FROM table1
The error that I get is:
Incorrect syntax near 'YEAR'.
As I mentioned in my comment, an alias cannot be an expression, it has to be a literal. As such the expressions you have tried to use are not allowed and generate syntax errors.
Normally, this sort requirement is the sign of a design flaw, or that you're trying to do something that should be in the presentation in the SQL layer. I'm going to assume the latter here. As a result, instead you should use static names for the columns, and then in your presentation layer, control the name of the columns there, so that when they are presented to the end user they have the names you want (for today that would be YEAR2022, YEAR2021 and YEAR2020). Then your query would just look like this:
select column1*2 AS ThisYear,
column1*3 AS YearPrior,
column1*4 AS Year2Prior
FROM dbo.table1;
How you change the names of the columns in your presentation layer is a completely different question (we don't even know what language you are using to write your application). If you want to ask about that, I suggest asking a new question (only if after you've adequately researched the problem and failed to find a solution), so that we can help you there.
Note that Though you can achieve a solution via dynamic SQL, I would strongly suggest it is the wrong solution here, and thus why I haven't given an answer providing a demonstration.

Simple CASE expression in SQL

I am new to SQL. I am trying to practice writing CASE expressions. Below is a query I have been working with.
SELECT bill,
'provider' as
case
when refer != '' THEN refer
WHEN render != '' THEN render
ELSE 'NULL'
END
FROM billing
This is the criteria for my query -
1) I need a new column in the select that is not part of the table. I have named it provider in the above query.
2) I need the new column's value to be the refer column's value if refer is not empty.
3) I need it to be equal to the render column's value if render is not empty.
4) I need it to be NULL if both are empty.
5) The output should look like
Bill Provider
123 Health
456 Org
789 NULL
The correct syntax is:
SELECT bill,
(CASE WHEN refer <> '' THEN refer
WHEN render <> '' THEN render
END) as provider
FROM billing;
Notes:
The column alias comes after the definition.
Although != works, <> is the tradition comparison operator for not equals.
Do not use single quotes for column aliases. Only use them for string and date constants.
You've already got a fine answer, but I figured I'd mention a few other commands to investigate while you're learning about CASE. They may not apply to your current problem, but you'll likely find over time that FILTER and COALESCE are equally worth knowing about. FILTER often works as a simpler-to-read alternative to CASE. Check it out while you're CASE, and you'll have another option for future problems. Here's a short write-up you might like:
https://medium.com/little-programming-joys/the-filter-clause-in-postgres-9-4-3dd327d3c852
I use FILTER for manually constructed pivot tables, and it's much simpler to construct and review in that situation.
COALESCE you may already know about. But, if not, it's super handy. Pass in a list of possible values, and get back the first one (reading left-to-right) that's not null. That can sometimes be what you need where you would otherwise have to write a CASE.
https://www.postgresql.org/docs/current/functions-conditional.html

'-999' used for all condition

I have a sample of a stored procedure like this (from my previous working experience):
Select * from table where (id=#id or id='-999')
Based on my understanding on this query, the '-999' is used to avoid exception when no value is transferred from users. So far in my research, I have not found its usage on the internet and other company implementations.
#id is transferred from user.
Any help will be appreciated in providing some links related to it.
I'd like to add my two guesses on this, although please note that to my disadvantage, I'm one of the very youngest in the field, so this is not coming from that much of history or experience.
Also, please note that for any reason anybody provides you, you might not be able to confirm it 100%. Your oven might just not have any leftover evidence in and of itself.
Now, per another question I read before, extreme integers were used in some systems to denote missing values, since text and NULL weren't options at those systems. Say I'm looking for ID#84, and I cannot find it in the table:
Not Found Is Unlikely:
Perhaps in some systems it's far more likely that a record exists with a missing/incorrect ID, than to not be existing at all? Hence, when no match is found, designers preferred all records without valid IDs to be returned?
This however has a few problems. First, depending on the design, user might not recognize the results are a set of records with missing IDs, especially if only one was returned. Second, current query poses a problem as it will always return the missing ID records in addition to the normal matches. Perhaps they relied on ORDERing to ease readability?
Exception Above SQL:
AFAIK, SQL is fine with a zero-row result, but maybe whatever thing that calls/used to call it wasn't as robust, and something goes wrong (hard exception, soft UI bug, etc.) when zero rows are returned? Perhaps then, this ID represented a dummy row (e.g. blanks and zeroes) to keep things running.
Then again, this also suffers from the same arguments above regarding "record is always outputted" and ORDER, with the added possibility that the SQL-caller might have dedicated logic to when the -999 record is the only record returned, which I doubt was the most practical approach even in whatever era this was done at.
... the more I type, the more I think this is the oven, and only the great grandmother can explain this to us.
If you want to avoid exception when no value transferred from user, in your stored procedure declare parameter as null. Like #id int = null
for instance :
CREATE PROCEDURE [dbo].[TableCheck]
#id int = null
AS
BEGIN
Select * from table where (id=#id)
END
Now you can execute it in either ways :
exec [dbo].[TableCheck] 2 or exec [dbo].[TableCheck]
Remember, it's a separate thing if you want to return whole table when your input parameter is null.
To answer your id = -999 condition, I tried it your way. It doesn't prevent any exception

PostgreSQL extract keys from jsonb, exception "cannot call jsonb_object_keys on a scalar"

I am trying to get my head around with jsonb in Postgres. There are quite a few issues here, What I wanted to do was something like:
SELECT table.column->>'key_1' as a FROM "table"
I tried with -> and also some combinations of brackets as well, but I was always getting nil in a.
So I tried to get all keys first to see if it is even recognizing jsonb or not.
SELECT jsonb_object_keys(table.column) as a FROM "table"
This threw an error:
cannot call jsonb_object_keys on a scalar
So, to check the column type(which I created, so I know it IS jsonb, but anyway)
SELECT pg_typeof(column) as a FROM "table" ORDER BY "table"."id" ASC LIMIT 1
This correctly gave me "jsonb" in the result.
values in the column are similar to {"key_1":"New York","key_2":"Value of key","key_3":"United States"}
So, I am really confused on what actually is going on here and why is it calling my json data to be scalar? What does it actually means and how to solve this problem?
Any help in this regard will be greatly helpful.
PS: I am using rails, posted this as a general question for the problem. Any rails specific solution would also work.
So the issue turned out to be OTHER than only SQL.
As I mentioned I am using rails(5.1), I had used default value '{}' for the jsonb column. And I was using a two-way serializer for the column by defining it in my model for the table.
Removing this serializer and adjusting the default value to {} actually solved the problem.
I think my serializer was doing something to the values, but still, in the database, it had correct value like i mentioned in the question.
It is still not 100% clear to me what was the problem. But it is solved anyway. If anyone can shed some light on what exactly the problem was, that will be great.
Hope this might help someone.
In my case the ORM layer somehow managed to wrote a null string into the JSON column and Postgres was happy with it. Trying to execute json_object_keys on such value resulted in the OP error.
I have managed to track down the place that allow such null strings and after fixing the code, I have also fixed the data with the following query:
UPDATE tbl SET col = '{}'::jsonb WHERE jsonb_typeof(col) <> 'object';
If you intentionally mix the types stored in the column (e.g. sometimes it is an object, sometimes array etc), you might want to filter out all rows that don't contain objects with a simple WHERE:
SELECT jsonb_object_keys(tbl.col) as a FROM tbl WHERE jsonb_typeof(col) = 'object';

SQL isnull error

While trying to do a select query using the isnull which, i've tried in 2 differents servers that are identical one to the other. (They both use the same procedure, dll, return page, they just change from one ip to the other)
SELECT * FROM
ITEM_TEST
WHERE ITEM_NAME = isnull(#ITEM_TESTE, ITEM_NAME)
The operation is working without problems in one of the servers, returning all options when the #ITEM_TESTE is NULL, while in the other, it returns ONLY the ones that are NOT NULL.
I'm using a sybase-based-application (version 12.5) called SQLdbx (version 3.14)
Case it's not so openly understood, #ITEM_TESTE is a variable given from the user that is optional, meaning it can be null where the ITEM_NAME accepts a STRING to it, while it's also option the ITEM_TEST is a table with more than 10 variables, i'm simplifing it. This search, however, want's all the possibles results even if ITEM_NAME is UNKOWN while using others variables to narrow down the search. (I thought about creating a search with an IF condition that excluded ITEM_NAME and it worked, but the it made the search so "laggy" due to perfomance issues.)
EDIT
Change the name of the variables to make it less confusing (both with the same name) and added an explaining for easier understanding
Also, due to copyright issues that i can't post the exact code here.
This is your where clause:
WHERE ITEM_TESTE = isnull(#ITEM_TESTE, ITEM_TESTE)
This where clause will never be true when ITEM_TESTE is NULL, because NULL = NULL evaluates to not true in the SQL world.
Presumably, you want:
WHERE (ITEM_TEST = #ITEM_TESTE OR #ITEM_TESTE IS NULL)
The way it was explained to me and has forever stuck after all of these years, is that NULL is not nothing, it is unknown, so you cannot use an equality check to verify two things you know nothing about are equally nothing. IS is checking that they are in the same unknown state, which has nothing to do with a value.
So as the others have said = NULL will never work, because = implies value comparison.