I have the following sample query which takes values from procedure parameters. The parameter can be either passed or default to null.
SELECT * FROM table
WHERE( table_term_code = '201931'
OR (table_term_code = '201931' and table_DETL_CODE ='CA02')
OR ( table_term_code = '201931' and table_ACTIVITY_DATE = sysdate)
OR ( table_term_code = '201931' and table_SEQNO = NULL));
i.e the user can input term code and not input any other parameter, or can input term code and table_DETL_CODE and not any other input parameter.
Same goes for the other 2 or conditions.
If a term code is passed and table_DETL_CODE is null, the query should return all the values for that term_code, whereas this query returns null.
Is there a way to achieve this without case or if conditions in PL/SQL?
If I understood you correctly, this might be what you're looking for:
select *
from your_table
where (table_term_code = :par_term_code or :par_term_code is null)
and (table_detl_code = :par_detl_code or :par_detl_code is null)
and (table_activity_date = :par_activity_date or :par_activity_date is null)
and (table_seqno = :par_seqno or :par_seqno is null)
The description seems to that you require user to enter table_term_code and then either none or exactly 1 of the other 3. If so then perhaps:
select *
from your_table
where table_term_code = :par_term_code
and ( (table_detl_code = :par_detl_code and :par_activity_date is null and :par_seqno is null)
or (table_activity_date = :par_activity_date and :par_detl_code is null and :par_seqno is null)
or (table_seqno = :par_seqno and :par_detl_code is null and :par_activity_date is null)
or (table_seqno is null and :par_detl_code is null and :par_activity_date is null)
);
There are two tables, school and term. The school record must be shown, but the term record may not yet exist, therefore, the term may be null (thus the left join). The left joined table must be filtered by date for the current term if it exists. Can this be done in LINQ?
select school.school_name, term.term_start, term.term_end
from school
left join term on school.school_id = term.school_id and term.term_start <= '2017-10-21' and term.term_end >= '2017-10-21'
where school.active = 1
order by school.school_name
UPDATE:
After some input I have a left join but if a school is missing a term I still cannot make the start and end dates show as null - the school doesn't show at all if I am missing a term, and I want the school to show in the first column. What am I missing?? Here is the latest LinqPad code.
var query = ((from sc in Schools.Where(s => s.Active == 1 )
join t in Terms on sc.School_id equals t.School_id into ts
from tsub in ts.DefaultIfEmpty()
select new {name = sc.School_name,
start = tsub.Term_start,
end = tsub.Term_end})
.Where (o => o.start <= DateTime.Now && o.end >= DateTime.Now))
.OrderBy( o => o.name);
query.Dump();
UPDATE #2
Here is a screen shot of the SQL result, and I am trying to achieve the same thing in LINQ:
var query = from sc in school.Where(s = > s.active == 1 )
join t in term on sc.school_id == t.school_id
select new {name = sc.school_name,
start = t.term_start,
end = term.term_end}
.Where (o => o.start <= '2017-10-21' && o.end >= '2017-10-21')
.OrderBy( o => o.school_name)
I finally figured it out. If you put the .Where() clause on the joined table you will get null values if there is no matching record. Here is the LinqPad LINQ statement that works and it runs perfectly in .NET MVC.
var query = ((from sc in Schools.Where(s => s.Active == 1 )
join t in Terms.Where(x => x.Term_start <= DateTime.Now && x.Term_end >= DateTime.Now) on sc.School_id equals t.School_id into ts
from tsub in ts.DefaultIfEmpty()
select new {name = sc.School_name,
start = tsub.Term_start,
end = tsub.Term_end})
.OrderBy( o => o.name));
query.Dump();
I'm looking to update multiple rows in PostgreSQL in one statement. Is there a way to do something like the following?
UPDATE table
SET
column_a = 1 where column_b = '123',
column_a = 2 where column_b = '345'
You can also use update ... from syntax and use a mapping table. If you want to update more than one column, it's much more generalizable:
update test as t set
column_a = c.column_a
from (values
('123', 1),
('345', 2)
) as c(column_b, column_a)
where c.column_b = t.column_b;
You can add as many columns as you like:
update test as t set
column_a = c.column_a,
column_c = c.column_c
from (values
('123', 1, '---'),
('345', 2, '+++')
) as c(column_b, column_a, column_c)
where c.column_b = t.column_b;
sql fiddle demo
Based on the solution of #Roman, you can set multiple values:
update users as u set -- postgres FTW
email = u2.email,
first_name = u2.first_name,
last_name = u2.last_name
from (values
(1, 'hollis#weimann.biz', 'Hollis', 'Connell'),
(2, 'robert#duncan.info', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;
Yes, you can:
UPDATE foobar SET column_a = CASE
WHEN column_b = '123' THEN 1
WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')
And working proof: http://sqlfiddle.com/#!2/97c7ea/1
For updating multiple rows in a single query, you can try this
UPDATE table_name
SET
column_1 = CASE WHEN any_column = value and any_column = value THEN column_1_value end,
column_2 = CASE WHEN any_column = value and any_column = value THEN column_2_value end,
column_3 = CASE WHEN any_column = value and any_column = value THEN column_3_value end,
.
.
.
column_n = CASE WHEN any_column = value and any_column = value THEN column_n_value end
if you don't need additional condition then remove and part of this query
Let's say you have an array of IDs and equivalent array of statuses - here is an example how to do this with a static SQL (a sql query that doesn't change due to different values) of the arrays :
drop table if exists results_dummy;
create table results_dummy (id int, status text, created_at timestamp default now(), updated_at timestamp default now());
-- populate table with dummy rows
insert into results_dummy
(id, status)
select unnest(array[1,2,3,4,5]::int[]) as id, unnest(array['a','b','c','d','e']::text[]) as status;
select * from results_dummy;
-- THE update of multiple rows with/by different values
update results_dummy as rd
set status=new.status, updated_at=now()
from (select unnest(array[1,2,5]::int[]) as id,unnest(array['a`','b`','e`']::text[]) as status) as new
where rd.id=new.id;
select * from results_dummy;
-- in code using **IDs** as first bind variable and **statuses** as the second bind variable:
update results_dummy as rd
set status=new.status, updated_at=now()
from (select unnest(:1::int[]) as id,unnest(:2::text[]) as status) as new
where rd.id=new.id;
Came across similar scenario and the CASE expression was useful to me.
UPDATE reports SET is_default =
case
when report_id = 123 then true
when report_id != 123 then false
end
WHERE account_id = 321;
Reports - is a table here, account_id is same for the report_ids mentioned above. The above query will set 1 record (the one which matches the condition) to true and all the non-matching ones to false.
The answer provided by #zero323 works great on Postgre 12. In case, someone has multiple values for column_b (referred in OP's question)
UPDATE conupdate SET orientation_status = CASE
when id in (66934, 39) then 66
when id in (66938, 49) then 77
END
WHERE id IN (66934, 39, 66938, 49)
In the above query, id is analogous to column_b; orientation_status is analogous to column_a of the question.
In addition to other answers, comments and documentation, the datatype cast can be placed on usage. This allows an easier copypasting:
update test as t set
column_a = c.column_a::number
from (values
('123', 1),
('345', 2)
) as c(column_b, column_a)
where t.column_b = c.column_b::text;
#Roman thank you for the solution, for anyone using node, I made this utility method to pump out a query string to update n columns with n records.
Sadly it only handles n records with the same columns so the recordRows param is pretty strict.
const payload = {
rows: [
{
id: 1,
ext_id: 3
},
{
id: 2,
ext_id: 3
},
{
id: 3,
ext_id: 3
} ,
{
id: 4,
ext_id: 3
}
]
};
var result = updateMultiple('t', payload);
console.log(result);
/*
qstring returned is:
UPDATE t AS t SET id = c.id, ext_id = c.ext_id FROM (VALUES (1,3),(2,3),(3,3),(4,3)) AS c(id,ext_id) WHERE c.id = t.id
*/
function updateMultiple(table, recordRows){
var valueSets = new Array();
var cSet = new Set();
var columns = new Array();
for (const [key, value] of Object.entries(recordRows.rows)) {
var groupArray = new Array();
for ( const [key2, value2] of Object.entries(recordRows.rows[key])){
if(!cSet.has(key2)){
cSet.add(`${key2}`);
columns.push(key2);
}
groupArray.push(`${value2}`);
}
valueSets.push(`(${groupArray.toString()})`);
}
var valueSetsString = valueSets.join();
var setMappings = new String();
for(var i = 0; i < columns.length; i++){
var fieldSet = columns[i];
setMappings += `${fieldSet} = c.${fieldSet}`;
if(i < columns.length -1){
setMappings += ', ';
}
}
var qstring = `UPDATE ${table} AS t SET ${setMappings} FROM (VALUES ${valueSetsString}) AS c(${columns}) WHERE c.id = t.id`;
return qstring;
}
I don't think the accepted answer is entirely correct. It is order dependent. Here is an example that will not work correctly with an approach from the answer.
create table xxx (
id varchar(64),
is_enabled boolean
);
insert into xxx (id, is_enabled) values ('1',true);
insert into xxx (id, is_enabled) values ('2',true);
insert into xxx (id, is_enabled) values ('3',true);
UPDATE public.xxx AS pns
SET is_enabled = u.is_enabled
FROM (
VALUES
(
'3',
false
,
'1',
true
,
'2',
false
)
) AS u(id, is_enabled)
WHERE u.id = pns.id;
select * from xxx;
So the question still stands, is there a way to do it in an order independent way?
---- after trying a few things this seems to be order independent
UPDATE public.xxx AS pns
SET is_enabled = u.is_enabled
FROM (
SELECT '3' as id, false as is_enabled UNION
SELECT '1' as id, true as is_enabled UNION
SELECT '2' as id, false as is_enabled
) as u
WHERE u.id = pns.id;
I don't know how to work with nested selects in LINQ.
How could I convert this SQl expression to LINQ?
Select i.ID, i.Impression,
(Select COUNT(ImpressionsId)
from DiaryImpressions
where DiaryPostsId = '2' AND ImpressionsId = i.ID) as Num from Impressions i
Seriously? DiaryPostsId is a string? Oh well...
from i in context.Impressions
select new {
i.ID,
i.Impressions,
Num = (from d in context.DiaryImpressions
where d.DiaryPostsId == "2"
&& d.ImpressionsId == i.ID
select d).Count()
}
from ...
select new {
i.Id,
i.Impression,
Count = context.DiaryImpressions.Count(d => d.DiaryPostsId == 2 && d.ImpressionsId == i.Id)
}
If you map your objects properly, you can use child relations directly:
Count = i.DiaryImpressions.Count(d => d.DiaryPostsId == 2)
I need to filter the SQL query result according to 3 conditions:
1. Location
2. Doctor Name
3. Specialty Name
Below is the sql query if all 3 conditions are not empty:
if (location != "" && doctor!="" && specialty!="")
select Location, ...
from clinicdoctors
where Location = #Location and DoctorName = #DoctorName and SpecialtyName = #SpecialtyName
}
if only location is empty,
if (location == "" && doctor!="" && specialty!="")
select Location, ...
from clinicdoctors
where Location is not null and DoctorName = #DoctorName and SpecialtyName = #SpecialtyName
...
If I wanna check all the conditions, I need to write eight if statements.
What should I do to simplify the code in this situation?
select Location, ...
from clinicdoctors
where
ISNULL(#Location,Location) = Location
and ISNULL(#DoctorName,DoctorName) = DoctorName
and ISNULL(#SpecialtyName,SpecialtyName) = SpecialtyName
I think it would be better to do this in the code than sql as you have done. Not really any way around it since the queries are so different, but a terse way to do it would be:
$loc_where = empty($loc) ? 'Location IS NOT NULL' : "Location = $loc";
$doc_where = empty($doc) ? 'AND DoctorName IS NOT NULL' : "AND DoctorName = $doc";
$spec_where = empty($spec) ? 'AND SpecialtyName IS NOT NULL' : "AND SpecialtyName = $spec";
query ... WHERE $loc_where $doc_where $spec_where