How to add conditional statement inside SQL query? - sql

Hi I am working on one SQL query. Below is my method name which executes query.
private string GetAggregatedOptionParametersByStyleIdCommand(string styleId, bool currentStore)
{
SELECT
opts.style, opts.option::text as {OptionKey}, opts.primary_colour, opts.secondary_colour, opts.brand_description, opts.description, params.*,
CASE WHEN {currentStore} == true THEN
FROM
rex.options opts
JOIN
rex.product_atoms atoms ON atoms.option_id = opts.option
JOIN
rex.parameters params ON atoms.id = params.product_atom_id
JOIN
rex.stores stores ON params.store = stores.id
WHERE
opts.style = '{styleId}'
}
Below is the structure of stores table.
CREATE TABLE rex.stores (
id serial NOT NULL,
close_date timestamp NOT NULL,
country text NULL,
distribution_centre text NULL,
"name" text NULL,
open_date timestamp NOT NULL,
CONSTRAINT "PK_stores" PRIMARY KEY (id)
);
So what I am trying to make is, Whenever the currentStore is true then I want to return the current store. Condition to check currentStore is
store.OpenDate <= currentDate &&
store.CloseDate >= currentDate
Whenever the currentStore is false I want to return all store. To check all store condition is
store.CloseDate >= currentDate
I am trying to add these conditions inside SQL query. I have added CASE WHEN {currentStore} == true THEN I am not sure how to add my closed store condition. Can anyone help me to complete this query? Any help would be appreciated. Thank you.

If you want to check for another possibility you can either add another WHEN or ELSE condition to your CASE statement. These need to come before the END.
For example:
CASE
WHEN x < 0 THEN 'negative'
WHEN x > 0 THEN 'positive'
ELSE 'zero'
END
I am not familiar with postgres, you may not need an END, and you may also be able to say CASE x WHEN > 0 THEN... WHEN < 0 ... meaning you only need to mention x once after CASE; again, this may not be a thing in postgres.

Related

CASE WHEN in request

I have a "user_activity_log" table that contains the fields "id", "client_id", "hitdatetime", and "action".
id
client_id
hitdatetime
action
2661715
17
2020-09-18 11:30:43
visit
2661716
17
2020-09-18 11:30:54
registration
2661717
17
2020-09-18 11:31:16
visit
It is necessary to output:
"client_id", from the input table
"visit_dt", that is associated to the "hitdatetime" field when the "action" equals to 'visit', otherwise it is null
"is_registration", that is associated to 1 if "action" equals to 'registration', otherwise it is 0
The CASE statement is mandatory for this query.
I've started writing the query, but I don't know what to put in place of the signs ???.
SELECT client_id,
CASE WHEN action = 'visit' THEN ??? ELSE 'NULL' END as visit_dt,
CASE WHEN action = 'registration' THEN '1' ELSE '0' END as is_registration
FROM user_activity_log;
Can you provide help?
Try with the following one:
SELECT client_id,
CASE WHEN action = 'visit'
THEN hitdatetime END AS visit_dt,
CASE WHEN action = 'registration'
THEN 1
ELSE 0 END AS is_registration
FROM user_activity_log;
Side notes:
if the ELSE clause of the CASE statement should evaluate to NULL, you are not required to specify it as it is default value
use numeric values in place of strings if the nature of your input should be numeric
always prefer using NULL instead of the corresponding "NULL" string, as sql provides a whole set of functions that can handle NULL values in a better way
is_registration should really be boolean. Also makes the query simpler:
SELECT client_id
, CASE WHEN action = 'visit' THEN hitdatetime END AS visit_dt
, action = 'registration' AS is_registration -- !
FROM user_activity_log;
If action can be NULL, so can be is_registration. If you want false instead of null, use one of these:
action IS NOT DISTINCT FROM 'registration' AS is_registration
Or:
COALESCE(action = 'registration', false) AS is_registration
Related:
Change varchar to boolean in PostgreSQL
Why does PostgreSQL not return null values when the condition is <> true
Best way to check for "empty or null value"

PostgreSQL conditional where clause

In my Ruby on Rails app I'm using blazer(https://github.com/ankane/blazer) and I have the following sql query:
SELECT *
FROM survey_results sr
LEFT JOIN clients c ON c.id = sr.client_id
WHERE sr.client_id = {client_id}
This query works really well. But I need to add conditional logic to check if client_id variable is present. If yes then I filter by this variable, if not then I not launching this where clause. How can I do it in PostgreSQL?
Check if its null OR your condition like this:
WHERE {client_id} IS NULL OR sr.client_id = {client_id}
The WHERE clause evaluate as follow: If the variable is empty, then the WHERE clause evaluate to true, and therefore - no filter. If not, it continue to the next condition of the OR
If anyone faced with the psql operator does not exist: bigint = bytea issue, here is my workaround:
WHERE ({client_id} < 0 AND sr.client_id > {client_id}) OR sr.client_id = {client_id}
Please consider that, client_id generally cannot be negative so you can use that information for eleminating the operation cast issue.
My solution:
I use spring data jpa, native query.
Here is my repository interface signature.
#Query(... where (case when 0 in :itemIds then true else i.id in :itemIds end) ...)
List<Item> getItems(#Param("itemIds) List<Long> itemIds)
Prior calling this method, I check if itemIds is null. If yes, I set value to 0L:
if(itemIds == null) {
itemIds = new ArrayList<Long>();
itemIds.add(0L);
}
itemRepo.getItems(itemIds);
My IDs starts from 1 so there is no case when ID = 0.

sql statement with an if inside of it?

I've got the following sql query which works. However I need help with the fields that have a /10000 calculation. Occasionally there will be no data in the field to be calculated, so my query below is returning a 0. How do I check for data > 0 before I perform the /10000 calculation?
SELECT
timesheet.customerID,
customer.customer,
timesheet.projectID,
project.project_title,
timesheet.chargeID,
charge.charge_description,
timesheet.notes,
timesheet.mon/10000,
timesheet.tues/10000,
timesheet.wed/10000,
timesheet.thurs/10000,
timesheet.fri/10000,
timesheet.sat/10000,
timesheet.sun/10000,
timesheet.lineID
FROM
timesheet_line timesheet
LEFT JOIN customer ON timesheet.customerID = customer.customerID
LEFT JOIN project ON timesheet.projectID = project.projectID
LEFT JOIN charge_rate charge ON timesheet.chargeID = charge.chargeID
WHERE
timesheet.timesheetID = '" & tTimesheetID & "' --VBA variable added here
ORDER BY
timesheet.lineID
You could do it like this (example column)
CASE timesheet.wed > 0 THEN timesheet.wed/10000 ELSE null END as wed,
if the value can be null then you have to do this:
CASE COALESCE(timesheet.wed,0) > 0 THEN timesheet.wed/10000 ELSE null END as wed,
You have a few options:
The COALESCE function is perfect when you want to translate possible NULL values to something else:
COALESCE(NullableColumn / 10000, DefaultValueIfNull)
-- btw., NULL divided by 10,000 should yield NULL, not 0.
Some SQL dialects (such as SQL Server's T-SQL) have a very similar function called ISNULL.
CASE is closer to an if:
CASE WHEN NullableColumn IS NOT NULL THEN NullableColumn / 1000 ELSE DefaultValue END

SQL regex and field

I want to change the query to return multiply values in extra_fields, how can I change the regex? Also I don't understand what extra_fields is - is it a field? If so why it is not called with the table prefix like i.extra_fields?
SELECT i.*,
CASE WHEN i.modified = 0 THEN i.created ELSE i.modified END AS lastChanged,
c.name AS categoryname,
c.id AS categoryid,
c.alias AS categoryalias,
c.params AS categoryparams
FROM #__k2_items AS i
LEFT JOIN #__k2_categories AS c ON c.id = i.catid
WHERE i.published = 1
AND i.access IN(1,1)
AND i.trash = 0
AND c.published = 1
AND c.access IN(1,1)
AND c.trash = 0
AND (i.publish_up = '0000-00-00 00:00:00'
OR i.publish_up <= '2013-06-12 22:45:19'
)
AND (i.publish_down = '0000-00-00 00:00:00'
OR i.publish_down >= '2013-06-12 22:45:19'
)
AND extra_fields REGEXP BINARY '(.*{"id":"2","value":\["[^\"]*1[^\"]*","[^\"]*2[^\"]*","[^\"]*3[^\"]*"\]}.*)'
ORDER BY i.id DESC
The extra_fields is a column of the #__k2_items table. The table qualifier can be omitted, because it is not ambiguous in this query. The column is JSON encoded. That is a serialization format used to store information which is not searchable by design. Applying a RegExp may work one day, but fail another day, since there is no guarantee for id preceeding value (as in your example).
The right way
The right way to filter this is to ignore the extra_fields condition in the SQL query an evaluate in the resultset instead. Example:
$rows = $db->loadObjectList('id');
foreach ($rows as $id => $row) {
$extra_fields = json_decode($row->extra_fields);
if ($extra_fields->id != 2) {
unset($rows[$id]);
}
}
The short way
If you can't change the database layout (which is true for extensions you want to keep updateable), you must split the condition into two, because there is no guarantee for a certain order of the subfields. For some reason, one day value may occur before id. So change your query to
...
AND extra_fields LIKE '%"id":"2"%'
AND extra_fields REGEXP BINARY '"value":\[("[^\"]*[123][^\"]*",?)+\]'
Prepare an intermediate table to hold the contents of extra_fields. Each extra_fields field will be converted into a series of records. Then do a join.
Create a trigger and cronjob to keep the temp table in sync.
Another way is to write UDF in Perl that will decode the field, but AFAIK it is not indexable in mysql.
Using an external search engine is out of scope.
Ok, i didnt want to change the db strucure, i gost some help and changed the regex intoAND extra_fields REGEXP BINARY '(.*{"id":"2","value":\[("[^\"]*[123][^\"]*",?)+\]}.*)'
and i got the right resaults
Thanks

How to make Linq to SQL translate to a derived column?

I have a table with a 'Wav' column that is of type 'VARBINARY(max)' (storing a wav file) and would like to be able to check if there is a wav from Linq to SQL.
My first approach was to do the following in Linq:
var result = from row in dc.Table
select new { NoWav = row.Wav != null };
The problem with the code above is it will retreive all the binary content to RAM, and this isn't good (slow and memory hungry).
Any idea how to have Linq query to translate into something like bellow in SQL?
SELECT (CASE WHEN Wav IS NULL THEN 1 ELSE 0 END) As NoWav FROM [Update]
Thanks for all the replies. They all make sense. Indeed, Linq should translate the != null correctly, but it didn't seem to effectively do it: running my code was very slow, so somehow my only explaination is that it got the binary data transfered over to the RAM.... but maybe I'm wrong.
I think I found a work around anyway somewhere else on stackoverflow: Create a computed column on a datetime
I ran the following query against my table:
ALTER TABLE [Table]
ADD WavIsNull AS (CASE WHEN [Wav] IS NULL Then (1) ELSE (0) END)
Now I'll update my DBML to reflect that computed column and see how it goes.
Are you sure that this code will retrieve the data to RAM?
I did some testing using LINQPad and the generated SQL was optimized as you suggest:
from c in Categories
select new
{
Description = c.Description != null
}
SELECT
(CASE
WHEN [t0].[description] IS NOT NULL THEN 1
ELSE 0
END) AS [Description]
FROM [Category] AS [t0]
What about this query:
var result = from row in dc.Table where row.Wav == null
select row.PrimaryKey
for a list of keys where your value is null. For listing of null/not null you could do this:
var result = from row in db.Table
select new
{ Key = row.Key, NoWav = (row.Wav == null ? true : false) };
That will generate SQL code similar to this:
SELECT [t0].[WavID] AS [Key],
(CASE
WHEN [t0].[Wav] IS NULL THEN 1
ELSE 0
END) AS [NoWav]
FROM [tblWave] AS [t0]
I'm not clear here, your SQL code is going to return a list of 1s and 0s from your database. Is that what you are looking for? If you have an ID for your record then you could just retrieve that single record with the a condition on the Wav field, null return would indicate no wav, i.e.
var result = from row in dc.Table
where (row.ID == id) && (row.Wav != null)
select new { row.Wav };