I tried to use CASE/WHEN inside Postgresql to check two colums, but the results are odd.
As it's shown in the image below, all the lines where "gain_value" is 8 AND "patrimony_value" have a higher value return a wrong result.
This is my statement:
select stop_value, gain_value, patrimony_value,
case
when patrimony_value >= gain_value then 1
else 2
end
from copy.copy_stop_gain csg
Since it's a pretty straightforwad "if/else", i'm really not sure what i could be doing wrong.
Can anyone show me where is my mistake?
Try casting string values to numbers (or perhaps change column type in schema)...
select stop_value, gain_value, patrimony_value,
case
when patrimony_value::INTEGER >= gain_value::INTEGER then 1
else 2
end
from copy.copy_stop_gain csg
Related
I need to select one and only 1 row of data based on an ID in the data I have. I thought I had solved this (For details, see my original question and my solution, here: PostgreSQL - Select only 1 row for each ID)
However, I now still get multiple values in some cases. If there is only "N/A" and 1 other value, then no problem.. but if I have multiple values like: "N/A", "value1" and "value2" for example, then my case statement is not sufficient and I get both "value1" and "value2" returned to me. This is the case statement in question:
CASE
WHEN "PQ"."Value" = 'N/A' THEN 1
ELSE 0
END
I need to give a unique integer value to each string value and then the problem will be solved. The question is: how do I do this? My first thought is to somehow convert the character values to ASCII and sum them up.. but I am not sure how to do that and also worried about performance. Is there a way to very simply assign a value to each string so that I can choose 1 value only? I don't care which one actually... just that it's only 1.
EDIT
I am now trying to create a function to add up the ASCII values of each character so I can essentially change my case statement to something like this:
CASE
WHEN "PQ"."Value" = 'N/A' THEN 9999999
ELSE SumASCII("PQ"."Value")
END
Having a small problem with it though.. I have added it as a separate question, here: PostgreSQL - ERROR: query has no destination for result data
EDIT 2
Thanks to #Bohemian, I now have a working solution, which is as follows:
CASE
WHEN "PQ"."Value" = 'N/A' THEN -1
ELSE ('x'||LPAD(MD5("PQ"."Value"),16,'0'))::bit(64)::bigint
END DESC
This will produce a "unique" number for each value:
('x'||substr(md5("PQ"."Value"),1,8))::bit(64)::bigint
Strictly speaking, there is a chance of a collision, but it's very remote.
If the result is "too big", you could try modulus:
<above-calculation> % 10000
Although collisions would then be a 0.01% chance, you should try this formula against all known values to ensure there are no collisions.
If you don't care which value gets picked, change RANK() to ROW_NUMBER(). If you do care, do it anyway, but also add another term after the CASE statement in ORDER BY, separated by a comma, with the logic you want - for example if you want the first value alphabetically, do this:
...
ORDER BY CASE...END, "PQ"."Value")
...
I'm trying to compare a value from a field but only using the last 3 values.
WHERE table1.FieldValue(-3) NOT LIKE table2.Fieldvalue
obviously (-3) doesn't work. I've tried converting it to a string then trying to play with it that way. But to no success.
Any suggestions welcome.
Thanks
EDIT:
I'm looking at postcodes.
So table1.Fieldvalue = N90HXF
and table2.Fieldvalue = N90
I want to trim the HXF off so I can compare the two.
You can use the LEFT() function to compare only the first characters of a string, exluding the last 3 from the value.
WHERE LEFT(table1.FieldValue, LEN(table1.FieldValue)-3) NOT LIKE table2.FieldValue
As I would see things from your request, you can exclude the values which are less than 3 characters from the results, so you would just add another condition in your WHERE clause, like:
WHERE LEN(table1.FieldValue) > 3
AND LEFT(table1.FieldValue, LEN(table1.FieldValue)-3) NOT LIKE table2.FieldValue
But if you do not want to exclude those values from your result, but you would rather that they are added at the end of your query, you can use a condition like:
WHERE LEFT(table1.FieldValue, CASE
WHEN LEN(table1.FieldValue) < 3
THEN table1.FieldValue + REPLICATE('', 3)
ELSE LEN(table1.FieldValue) - 3
END) NOT LIKE table2.FieldValue
ORDER BY LEN(table1.FieldValue) DESC
The above condition will pad (add) 3 whitespaces to all of your values, so that the LEFT() function will not result in an error even if the value has less than 3 characters.
I've tried to follow this answer (to a different problem that what I have). However, I'm getting the error telling me that the syntax is incorrect near IF.
select if(1 < 2, 3, 4) as Reply
from Unit
The above is the exact syntax I'm using (the table Unit exists but has nothing to do with the values, of course. Sometimes I just wish to be able to manipulate some columns for better visibility when I play in SQL Studio.
Please note that I'm not asking about how to coalesce nor how to handle null values. If it appears like if I am, then either you've misunderstood the question or I haven't been clear with my explanation. Sorry about that in advance.
You are looking for the case clause:
select
case when 1 < 2
then 3
else 4 end as Reply
from Unit
Or if you only wish to see the result once (as opposed to for each row in the table):
select
case when 1 < 2 then 3 else 4 end as Reply
I believe this is the syntax you are looking for, it works from sqlserver 2012:
SELECT IIF( 1 < 2, 3, 4)
The syntax is:
IIF ( boolean_expression, true_value, false_value )
Problem while placing oracle query inside of the oracle if else statements
select workgroupid, maxchats,
case
when a.maxchats ='-1' then
(select propvalue from ofproperty where name = 'xmpp.live.defaults.maxchats')
else
null (1)
end as aaaa
from fpworkgroup a;
when im placing maxchats at 1 position im getting error,,
how can i resolve this....?
help me..
thanks in advance
It's hard to understand your question but it sounds like you're trying to put maxchats in place of null (1) and it gives you an error?
If that is correct, I'm guessing that the error is that fpworkgroup.maxchats and ofproperty.propvalue have different column types that do not line up. All branches of a CASE must return the same column type. You cannot, for example, return an int from one branch and return a varchar from another.
You'll have to cast one or the other so that they return the same type.
I am trying to get some percentage data from a stored procedure using code similar to the line below. Obviously this is going to cause a (Divide by zero error encountered) problem when base.[XXX_DataSetB] returns 0 which may happen some of the time.
Does anyone know how i can deal with this in the most efficient manner?
Note: There would be about 20+ lines looking like the one below...
cast((base.[XXX_DataSetB] - base.[XXX_DataSetA]) as decimal) /
base.[XXX_DataSetB] as [XXX_Percentage]
I guess it depends on what behaviour you expect when XXX_DataSetB is zero.
If you don't want any rows returned that might cause an error, you can easily filter out those rows by adding where XXX_DataSetB <> 0 to your query.
If you would like problem rows to be NULL then you could use a case statement, or something like this:
cast(([XXX_DataSetB] - [XXX_DataSetA]) as decimal) / nullif([XXX_DataSetB], 0)
I'd force the average to null by making the bottom term null instead of zero:
cast((base.[XXX_DataSetB] - base.[XXX_DataSetA]) as decimal)
/ case when base.[XXX_DataSetB] = 0 then null
else base.[XXX_DataSetB] end as [XXX_Percentage]