Case when no record then error (postgresql) - postgresql-9.1

Struggling with a simple problem and find no solution.
https://ideone.com/Hisu8H (sqlfiddle mini) Should be two rows, but only one OK appears.
If there is a record there should be an OK result. If no records there should be ERROR result.
SELECT
CASE WHEN (SELECT count(*) from code)=0 THEN 'ERROR' else 'OK' end
FROM code
WHERE "CODE_ID"='EXISTS'
The problem is that if the CODE_ID exists, there will be a line OK but if the record is missing there will be no line fetched at all.
In a simple query this works. But not as a condition!
SELECT COALESCE(count(*), 0) FROM code
WHERE "CODE_ID"='ERROR'
Thanks in advance for any clue!

If there is no row that matches the condition then nothing is returned and you can't count it.
To return information about values that are used in a condition but do not exist in the database you typically use an outer join on the list of values:
select t.id,
code.code_id
from (
values ('error'), ('test')
) as t (id)
left join code on code.code_id = t.id;
This essentially a where code_id in ('error', 'test') query that also returns those values from the in list that do not exist in the table.
This can then be used to identify the missing values:
select t.id,
case when code.code_id is null then 'Error' else 'OK' end as status
from (
values ('error'), ('test')
) as t (id)
left join code on code.code_id = t.id;

Related

How to concatenate a Select query inside a INSTR() in SQLite?

I was trying to order a result set by the order of the values in an IN() clause.
SELECT * FROM CrossReference WHERE cross_reference_id IN (SELECT Id FROM FilteredIds)
So I tried to find a function such as MySql FIELD(). Then I found these answers (answer1, answer2) which explain how to do the exact thing on SQLite using the INSTR().
SELECT *, INSTR(',GDBR10,GDBR5,GDBR30,', ',' || ticker || ',') POS
FROM tbl
WHERE POS>0
ORDER BY POS;
So it's working as expected, but I want to populate the ids dynamically using a select query. I tried many approaches, but nothing seemed to work. Here is the last one I tried. It gave me just one result row (a result related to the first filterId).
SELECT *, INSTR (','||(SELECT id FROM FilteredIds)||',', ',' || cross_reference_id || ',') POS FROM CrossReference WHERE POS>0 ORDER BY POS;
So I guess I'm making some kind of mistake when concatenating the SELECT query with the rest of the code. Because when I manually enter the filtered Ids it works and returns results according to the entered filter ids.

SQLite How to Include Records Where NULL in Objective C?

I’m attempting to count records that match specific criteria, including one field being null, but including the null clause results in no records being found.
If I output the contents of the field, it comes back as “(null)”. I’ve tried IS NULL and ISNULL, both of which appear that they should work when looking at other sources, but they both fail for me.
SELECT calls.contact_number, calls.contact_name, COUNT(notes.id) AS note_count
FROM calls LEFT JOIN notes on calls.id = notes.call_id
WHERE calls.contact_number = "123" AND notes.group_id ISNULL
GROUP BY calls.contact_number
This returns no records, whereas I’m expecting it to return one.
Move the condition in the ON clause:
SELECT calls.contact_number, calls.contact_name, COUNT(notes.id) AS note_count
FROM calls LEFT JOIN notes
ON calls.id = notes.call_id AND notes.group_id IS NULL
WHERE calls.contact_number = "123"
GROUP BY calls.contact_number, calls.contact_name
After grabbing a copy of the database, the notes.group_id field was determined to be an integer type, and the record in question actually contained a 0.
The successful query ended up being
SELECT calls.contact_number, calls.contact_name, COUNT(notes.id) as note_count
FROM calls LEFT JOIN notes
ON calls.id = notes.call_id
WHERE calls.contact_number = “123” AND (notes.group_id IS NULL OR notes.group_id = 0)
GROUP BY calls.contact_number
Not sure why the NSLog output of the returned value for group_id was ‘(null)’, some weird conversion?

ORA-01427: single-row subquery returns more than one row when inserting multiple rows

I am trying to assign or give all permissions of a user to another given user, 13053 but facing this Oracle error, ORA-01427: single-row subquery returns more than one row and i know exactly which part of my SQL statement shown below is returning this error but failed to handle it because what i want to achieve is to give those multiple rows returned to the given user with an id of 13053.
My attempt
INSERT INTO userpermissions (
userid,permissionid
) VALUES (
13053,( SELECT permissionid
FROM userpermissions
WHERE userid = ( SELECT userid
FROM users
WHERE username = '200376'
)
)
);
Any help ?
Thanks in advance.
A rewrite ought to do the trick:
INSERT INTO USERPERMISSIONS(
USERID,
PERMISSIONID
)
SELECT 13053 AS USERID,
p.PERMISSIONID
FROM USERPERMISSIONS p
WHERE p.userid = (SELECT userid FROM users WHERE username = '200376');
The problem with the original insert is that you are using single-row insert syntax when you are really trying to insert a set of rows.
Including the target userid as a literal is one way to make the set of rows look the way I am assuming you intend.

Why did I get the ""exact fetch returns more than requested number of rows" when I use cursor already?

I am using the cursor to write the following codes, so that the cursor can pick up multiple lines. However, it still gives me the error message "exact fetch returns more than requested number of rows". Isn't that the cursor will retrieve data one line at a time. Why is this message still showing?
create or replace trigger e
before delete on enrollment
for each row
declare
get_tid scorest.tid%type;
get_ferm scorest.ferm%type;
get_sect scorest.sect%type;
get_name scorest.name%type;
get_score scorest.score%type;
cursor findenrolls(atid in scorest.tid%type,
aferm in scorest.ferm%type,
asect in scorest.sect%type)
is select * from scorest;
begin
for findenrolls_rec in findenrolls(:old.tid, :old.ferm, :old.sect) loop
select tid, ferm, sect, name, score
into get_tid, get_ferm, get_sect, get_name, get_score
from scorest
where scorest.tid=:old.tid
and scorest.ferm=:old.ferm
and scorest.sect=:old.sect;
insert into deleted_scores values (get_tid, get_ferm, get_sect, get_name, get_score);
delete from scorest
where tid=get_tid
and ferm=get_ferm
and sect=get_sect
and name=get_name;
end loop;
end;
Your error come from this statement part. select into must return exact one record.
select tid, ferm, sect, name, score
into get_tid, get_ferm, get_sect, get_name, get_score
from scorest
where scorest.tid=:old.tid
and scorest.ferm=:old.ferm
and scorest.sect=:old.sect;
You must rewrite your code make it work. Without knowing you use case it can be harder, but you can try this.
CREATE OR REPLACE
TRIGGER e before DELETE
ON enrollment
FOR EACH row
BEGIN
FOR get IN (
SELECT tid
, ferm
, sect
, name
, score
FROM scorest
WHERE scorest.tid=:old.tid
AND scorest.ferm =:old.ferm
AND scorest.sect =:old.sect
)
LOOP
INSERT
INTO deleted_scores VALUES
( get.tid
, get.ferm
, get.sect
, get.name
, get.score
);
DELETE
FROM scorest
WHERE tid=get.tid
AND ferm =get.ferm
AND sect =get.sect
AND name =get.name;
END LOOP;
END;
How you can see the explicit cursor is gone and replaced by an implicit one, this look more appropriate for this case.
error is coming due to duplicate data in scorest table based on tid , ferm ,sect
you can check this by
select tid , ferm ,sect from scorest having count(1)>1
group by tid , ferm ,sect;
if you don't need duplicates when you can put one more condition in your select statement
select tid, ferm, sect, name, score
into get_tid, get_ferm, get_sect, get_name, get_score
from scorest
where scorest.tid=:old.tid
and scorest.ferm=:old.ferm
and scorest.sect=:old.sect;
and rownum =1
else you can which to approach suggested by "Ftaveras ".

Insert into Table with the first column being a Sequence

I am trying to use an Insert, Sequence and Select * to work together.
INSERT INTO BRK_INDV
Select * from (Select brk_seq.NEXTVAL as INDV_SEQ, a.*
FROM (select to_date(to_char(REQUEST_DATETIME,'DD-MM-YYYY'),'DD-MM-YYYY') BUSINESS_DAY, to_char(REQUEST_DATETIME,'hh24') src_hour,
CASE tran_type
WHEN 'V' THEN 'Visa'
WHEN 'M' THEN 'MasterCard'
ELSE tran_type
end text,
tran_type, count(*) as count
from DLY_STATS
where 1=1
AND to_date(to_char(REQUEST_DATETIME,'DD-MM-YYYY'),'DD-MM-YYYY') = '09-FEB-2015'
group by to_date(to_char(REQUEST_DATETIME,'DD-MM-YYYY'),'DD-MM-YYYY'),to_char(REQUEST_DATETIME,'hh24'),tran_type order by src_hour)a);
This gives me the following error:
ERROR at line 2:
ORA-02287: sequence number not allowed here
I tried to remove the order by and still the same error.
However, if I only run
Select brk_seq.NEXTVAL as INDV_SEQ, a.*
FROM (select to_date(to_char(REQUEST_DATETIME,'DD-MM-YYYY'),'DD-MM-YYYY') BUSINESS_DAY, to_char(REQUEST_DATETIME,'hh24') src_hour,
CASE tran_type
WHEN 'V' THEN 'Visa'
WHEN 'M' THEN 'MasterCard'
ELSE tran_type
end text,
tran_type, count(*) as count
from DLY_STATS
where 1=1
AND to_date(to_char(REQUEST_DATETIME,'DD-MM-YYYY'),'DD-MM-YYYY') = '09-FEB-2015'
group by to_date(to_char(REQUEST_DATETIME,'DD-MM-YYYY'),'DD-MM-YYYY'),to_char(REQUEST_DATETIME,'hh24'),tran_type order by src_hour)a;
It shows me proper entries. Then, why is select * not working for that?
Kindly help.
I see what you're trying to do. You want to insert rows into the BRK_INDV table in a particular order. The sequence number, which I assume will be the primary key of BRK_INDV, will be generated sequentially in the sorted order of the input rows.
You are working with a relational database. One of the first characteristics we all learn about a relational database is that the order of the rows in a table is insignificant. That's just a fancy word for fugitaboutit.
You cannot assume that a select * from table will return the rows in the same order they were written. It might. It might for quite a long time. Then something -- the number of rows, the grouping of some column values, the phase of the moon -- something will change and you will get them out in a seemingly totally random order.
If you want order, it must be imposed in the query, not the insert.
Here's the statement you should be executing:
INSERT INTO BRK_INDV
With
Grouped( Business_Day, Src_Hour, Text, Tran_Type, Count )As(
Select Trunc( Request_Datetime ) Business_Day,
To_Char( Request_Datetime, 'hh24') Src_Hour,
Case Tran_Type
When 'V' Then 'Visa'
When 'M' Then 'MasterCard'
Else Tran_Type
end Text,
Tran_Type, count(*) as count
from DLY_STATS
Where 1=1 --> Generated as dynamic SQL?
And Request_Datetime >= Date '2015-02-09'
And Request_Datetime < Date '2015-02-10'
Group By Trunc( Request_Datetime ), To_Char( Request_Datetime, 'hh24'), Tran_Type
)
Select brk_seq.Nextval Indv_Seq, G.*
from Grouped G;
Notice there is no order by. If you want to see the generated rows in a particular order:
select * from Brk_Indv order by src_hour;
Since there could be hundreds or thousands of transactions in any particular hour, you probably order by something other than hour anyway.
In Oracle, the trunc function is the best way to get a date with the time portion stripped away. However, you don't want to use it in the where clause (or, aamof, any other function such as to_date or to_char)as that would make the clause non-sargable and result in a complete table scan.
The problem is that you can't use a sequence in a subquery. For example, this gives the same ORA-02287 error you are getting:
create table T (x number);
create sequence s;
insert into T (select * from (select s.nextval from dual));
What you can do, though, is create a function that returns nextval from the sequence, and use that in a subquery:
create function f return number as
begin
return s.nextval;
end;
/
insert into T (select * from (select f() from dual));

Resources