How to display 0 in count? - sqlite

How can I display 0 if there is no qualification matching?
My current query is:
select s.sname, count(*) as number
from sailor s, boat b
where s.rating >= b.rating
group by s.sname
order by number desc;
And the result I got is:
a 3
b 3
c 2
However, it is not really what I am trying to achieve. I would like to display the result like this:
a 3
b 3
c 2
d 0
e 0
I try to change count() to isnull(count(), 0) or coalesce(count(*), 0) but it doesnt correct in this case.
CREATE TABLE sailor (
sname character varying primary key,
rating integer
);
create table boat (
bname character varying primary key,
color character varying,
rating integer
);

This may help you
select s.sname,(select count(*)
from boat b
where s.rating >= b.rating
) t
from sailor s
order by t desc;
SQLFIDDLE

You are using an inner join, which returns only rows when data in both tables matches.
To return sailors without any matching boat, use an outer join:
select s.sname, count(*) as number
from sailor s
left join boat b on s.rating >= b.rating
group by s.sname
order by number desc;

Related

HANA: Want to include offices that is having 0 value also

I have 4 offices in the table OFFICE_DETAILS which are a,b,c,d.
The below query outputs offices which are having any lab and rad count, so it is including all offices except for c
office_name lab_count rad_count
a 5 0
b 1 2
d 3 1
I want the output to be as follows:
office_name lab_count rad_count
a 5 0
b 1 2
c 0 0
d 3 1
what is the change required in the following code
SELECT d.OFFICE_name AS "OFFICE_NAME" ,
count(CASE
WHEN c.LAB_TYPE LIKE 'L' THEN 1
END) AS "LAB_TEST_COUNT",
count(CASE
WHEN c.LAB_TYPE in ('X','O') THEN 1
END) AS "RAD_TEST_COUNT"
FROM
DOCTOR_CONSULT a
INNER JOIN consult_labtest b
on(a.CONSULT_ID=b.CONSULT_ID)
INNER JOIN test_setup c
on(b.LABTEST_ID=c.TEST_ID)
INNER JOIN OFFICE_DETAILS d
on(a.OFFICE_ID=D.OFFICE_ID)
INNER JOIN USER_SETUP e
on(a.DOCTORS_ID = e.USER_ID)
INNER JOIN DEPARTMENT_SETUP f
ON(a.DEPARTMENT_ID = f.DEPARTMENT_ID)
INNER JOIN TEST_CATEGORY g
ON (c.CATEGORY_ID=g.CATEGORY_ID)
WHERE
c.LAB_TYPE IN ('L','X','O') --'L'-> Laboratory, 'X'-> Radiology
AND c.ACTIVE_STATUS='Y'
AND d.ACTIVE_STATUS='Y'
AND g.ACTIVE_STATUS='Y'
AND
a.CONSULT_DATE BETWEEN CURRENT_DATE AND CURRENT_DATE
AND
d.ACTIVE_STATUS='Y'
AND
a.EMPLOYEE_ID NOT IN ('NEW RECRUITMENT 380', '0000', 'army', 'undefined')
GROUP BY d.OFFICE_NAME
ORDER BY d.OFFICE_NAME ASC;
To retrieve result rows from joined tables that do not have matching rows (e.g. no matching entries in OFFICE_DETAILS table) SQL provides OUTER JOINS.
Join the details tables as outer joins and handle the resulting NULLs in the projection.
This is the most common approach to address this requirement.
Alternatively, the details tables could contain a special “no match” record that is used to match in an OR branch of the join condition. Some data warehouses do this to avoid NULLs.
I did by using LEFT JOIN. I am getting the required output
CREATE VIEW ECLINIC_KNG.VIEW_LABRADTESTS_OFFICE_COUNT_TODAY AS
SELECT ROW_NUMBER() OVER() AS row_num,
v1.OFFICE_NAME,
v1.LAB_TEST_COUNT,
v1.RAD_TEST_COUNT
FROM
(
SELECT od.OFFICE_NAME as "OFFICE_NAME",
(CASE WHEN v.LAB_TEST_COUNT IS NULL THEN 0 ELSE v.LAB_TEST_COUNT END) AS
"LAB_TEST_COUNT",
(CASE WHEN v.RAD_TEST_COUNT IS NULL THEN 0 ELSE v.RAD_TEST_COUNT END) AS
"RAD_TEST_COUNT"
FROM
OFFICE_DETAILS od
LEFT JOIN
(
SELECT d.OFFICE_NAME ,
count(CASE WHEN c.LAB_TYPE LIKE 'L' THEN 1 END) AS "LAB_TEST_COUNT",
count(CASE WHEN c.LAB_TYPE in ('X','O') THEN 1 END) AS "RAD_TEST_COUNT"
FROM
ECLINIC_KNG.DOCTOR_CONSULT a
INNER JOIN ECLINIC_KNG.consult_labtest b
on(a.CONSULT_ID=b.CONSULT_ID)
INNER JOIN ECLINIC_KNG.test_setup c
on(b.LABTEST_ID=c.TEST_ID)
INNER JOIN ECLINIC_KNG.OFFICE_DETAILS d
on(a.OFFICE_ID=D.OFFICE_ID)
INNER JOIN ECLINIC_KNG.USER_SETUP e
on(a.DOCTORS_ID = e.USER_ID)
INNER JOIN ECLINIC_KNG.DEPARTMENT_SETUP f
ON(a.DEPARTMENT_ID = f.DEPARTMENT_ID)
INNER JOIN ECLINIC_KNG.TEST_CATEGORY g
ON (c.CATEGORY_ID=g.CATEGORY_ID)
WHERE
c.LAB_TYPE IN ('L','X','O') --'L'-> Laboratory, 'X'-> Radiology
AND c.ACTIVE_STATUS='Y'
AND d.ACTIVE_STATUS='Y'
AND g.ACTIVE_STATUS='Y'
AND a.CONSULT_DATE BETWEEN CURRENT_DATE AND CURRENT_DATE
AND d.ACTIVE_STATUS='Y'
AND a.EMPLOYEE_ID NOT IN ('NEW RECRUITMENT 380', '0000', 'army', 'undefined')
GROUP BY d.OFFICE_NAME
ORDER BY d.OFFICE_NAME ASC
)AS v
on(od.OFFICE_NAME=v.OFFICE_NAME)
WHERE od.ACTIVE_STATUS='Y'
ORDER BY od.OFFICE_NAME
)AS v1

SQLITE get next row after ORDERBY

I need to get the next row from an ORDERBY query
I have 2 columns, ID(Primary key), Age(float) in a table T and I need something like the following
SELECT ID FROM T WHERE !> (inputted ID) + 1 rowID/Next row <! ORDERBY Age (then primary key, but I suspect if the Age values are the same SQLite would default to order by primary key anyway) LIMIT 1
Essentially it would select the next row after the inputted ID in the ordered table, its the next row / rowID + 1 I am not sure how to get.
As suggested here is a data set as an example
https://dbfiddle.uk?rdbms=sqlite_3.27&fiddle=19685ac20cc42041a59d318a01a2010f
ID Age
1 12.2
2 36.8
3 22.5
4 41
5 16.7
I am attempting to get the the following row from the ordered (by age) list given a specific ID
ID Age
1 12.2
5 16.7
3 22.5
2 36.8
4 41
Something similar to
SELECT ID FROM OrderedInfo WHERE ID = 5 ORDER BY Age ASC LIMIT 1 OFFSET 1;
My expected result would be '3' from the example data above
I have expanded the data set to include duplicate entries as I didn't implicitly state it could have such data - as such forpas answer works for the first example with no duplicate entries - thanks for your help
https://dbfiddle.uk?rdbms=sqlite_3.27&fiddle=f13d7f5a44ba414784547d9bbdf4997e
Use a subquery for the ID that you want in the WHERE clause:
SELECT *
FROM OrderedInfo
WHERE Age > (SELECT Age FROM OrderedInfo WHERE ID = 5)
ORDER BY Age LIMIT 1;
See the demo.
If there are duplicate values in the column Age use a CTE that returns the row that you want and join it to the table so that you expand the conditions:
WITH cte AS (SELECT ID, Age FROM OrderedInfo WHERE ID = 5)
SELECT o.*
FROM OrderedInfo o INNER JOIN cte c
ON o.Age > c.Age OR (o.Age = c.Age AND o.ID > c.ID)
ORDER BY o.Age, o.ID LIMIT 1;
See the demo.

Case statement based on partition of data

I'm trying to categorize my data based on the existence of text within a variable for each id that I have. For example:
ID Groupname
1 A
1 B
1 F
2 D
2 B
2 C
The result I want would be
ID Groupname Category
1 A AF
1 B AF
1 F AF
2 D D
2 B D
2 C D
I want to do something like the following but I cannot get it to work
Select * ,
CASE WHEN A,F in groupname (partition by id) THEN AF
WHEN D in groupname (partition by id) THEN D
....
ELSE null END
FROM table
Answers in postgres/redshift would greatly be appreciated!
EDIT:
I fixed the problem with F that JNevill brought up.
EDIT2:
One user suggested a simple solution that works if you only need 1 combination. E.g. If i see F or A then it's AF. But if I need to see A and F it will not work.
Here is the simple solution:
WHEN sum(CASE WHEN combo in (20,28,19,27) then 1 end) over (partition by log_id)=1 then 1000
If i want combinations I have to do the following which creates very long code. Is there an easier way to do this?
WHEN sum(CASE WHEN combo in (20,28,19,27) then 1 end) over (partition by log_id)=1
and sum(CASE WHEN groupid in (1048,598,428) then 1 end) over (partition by log_id)=1
then 1000
you're right about case with partitioning, it just requires conditional aggregate
select
*
,case
when sum(case when groupname in ('A','F') then 1 end) over (partition by id)=1 then 'AF'
when sum(case when groupname in ('D') then 1 end) over (partition by id)=1 then 'D'
end as category
from t
one note is that if you want only the pair of A and F to make AF category it's not possible with this syntax... count(distinct case...) over () returns an error and requires more complex query, but from what I see you don't need it since F is not in your sample data

SQL syntax error or missing database (near "(": syntax error) when using union

I am trying to use union but i get this vague syntax error. I Can get each query to run seperately, but when i try to use union i get this error.
(SELECT s.sname, COUNT(s.sname) AS number
FROM sailor s, boat b
WHERE b.rating <= s.rating
GROUP BY s.sname)
UNION
(SELECT s.sname, 0 AS number
FROM sailor s
WHERE NOT EXISTS(
SELECT * FROM boat b
WHERE s.rating >= b.rating));
In SQL, only subqueries use parentheses. In a compound query, the individual SELECTs must be written without them:
SELECT s.sname, COUNT(s.sname) AS number
FROM sailor s, boat b
WHERE b.rating <= s.rating
GROUP BY s.sname
UNION
SELECT s.sname, 0 AS number
FROM sailor s
WHERE NOT EXISTS(
SELECT * FROM boat b
WHERE s.rating >= b.rating);
And in this specific case, you might just want to use an outer join:
SELECT s.sname,
IFNULL(COUNT(b.rating), 0) AS number
FROM sailor AS s
LEFT JOIN boat AS b
ON b.rating <= s.rating;

Zipping rows with the same "key" while joining tables

I have two tables, one with objects, one with properties of the objects. Both tables have a personal ID and a date as "key", but since multiple orders of objects can be done by one person on a single day, it doesn't match well. I do know however, that the entries are entered in the same order in both tables, so it is possible to join on the order, if the personID and date are the same.
This is what I want to accomplish:
Table 1:
PersonID Date Object
1 20-08-2013 A
2 13-11-2013 B
2 13-11-2013 C
2 13-11-2013 D
3 21-11-2013 E
Table 2:
PersonID Date Property
4 05-05-2013 $
1 20-08-2013 ^
2 13-11-2013 /
2 13-11-2013 *
2 13-11-2013 +
3 21-11-2013 &
Result:
PersonID Date Object Property
4 05-05-2013 $
1 20-08-2013 A ^
2 13-11-2013 B /
2 13-11-2013 C *
2 13-11-2013 D +
3 21-11-2013 E &
So what I want to do, is join the two tables and "zip" the group of entries that have the same (PersonID,Date) "key".
Something called "Slick" seems to have this (see here), but I'd like to do it in SQLite.
Any advice would be amazing!
You are on the right track. Why not just do a LEFT JOIN between the tables like
select t2.PersonID,
t2.Date,
t1.Object,
t2.Property
from table2 t2
left join table1 t1 on t2.PersonID = t1.PersonID
order by t2.PersonID
Use a additional column to make every key unique in both tables. For example in SQLite you could use RowIDs to keep track of the order of insertion. To store this additional column in the database itself might be useful for other queries as well, but you do not have to store this.
First add the column ID to both tables, the DDL queries should now look like this: (make sure you do not add the primary key constraint until both tables are filled.
CREATE TABLE table1 (
ID,
PersonID,
Date,
Object
);
CREATE TABLE table2 (
ID,
PersonID,
Date,
Property
);
Now populate the ID column. You can adjust the ID to your liking. Make sure you do this for table2 as well:
UPDATE table1
SET ID =(
SELECT table1.PersonID || '-' || table1.Date || '-' || count( * )
FROM table1 tB
WHERE table1.RowID >= tB.RowID
AND
table1.PersonID == tB.PersonID
AND
table1.Date == tB.Date
);
Now you can join them:
SELECT t2.PersonID,
t2.Date,
t1.Object,
t2.Property
FROM table2 t2
LEFT JOIN table1 t1
ON t2.ID = t1.ID;

Resources