select count from table upon other table - sql

i have two tables (main_table) and (sub_table) related by person_id ..now i want to select person_id from main table and count of records in sub_table that related to main_table where records in sub_table not equal 'eco' .. now the problem is when i make this .. the query get only person_id that not equal 'eco' ... but i want from query to select every person_id and select count 0 if person_id in sub_table equal 'eco' :
SELECT m.person_id, COUNT(*) AS eco FROM (SELECT person_id FROM Main_table
WHERE (person_id ='c')AS m INNER JOIN
(SELECT person_id
FROM sub_table
WHERE person_status != 'eco'
GROUP BY person_id) AS eco ON eco.person_id = m.person_id GROUP BY m.person_id

The problem is that you are INNER joining to your sub_table, so you are by definition limiting the results to only people with an entry in this table that does not equal eco.
I think you can do this by simply left joining to your sub table, with the person_status in the join criteria:
SELECT m.Person_ID,
COUNT(s.Person_ID) AS NonEcoCount
FROM Main_Table m
LEFT JOIN sub_table s
ON s.Person_ID = m.Person_ID
AND s.person_status != 'eco'
GROUP BY m.Person_ID;

SELECT m.person_id,
countNonEco = (SELECT COUNT(*) FROM sub_table s
WHERE m.person_id = s.person_id
AND (s.person_status IS NULL OR s.person_status <> 'eco'))
FROM Main_table m

Related

JOIN 2 tables ORDER BY SUM value

I have 2 tables: 1st is comment, 2nd is rating
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
ORDER BY b.total_rating DESC
I tried the above SQL but doesn't work!
Object is to display a list of comments order by rating points of each comments.
SELECT s.* FROM (
SELECT * FROM comment_table a
INNER JOIN (SELECT comment_id, SUM(rating_value) AS total_rating FROM rating_table GROUP BY comment_id) b
ON a.comment_id = b.comment_id
) AS s
ORDER BY s.total_rating DESC
Nest it inside an another select. It will then output the data in the correct order.

Can I sum the count of two columns from two different tables?

I'm trying to add together the counts of two different tables and group them by the same variable
Here is what I have so far:
SELECT a.storenumber,
Count (howmanytotal) AS total_counts_store
FROM (
SELECT month_counts.howmany,
new_counts.howmany) AS howmanytotal
from (
SELECT a.storenumber,
count (b.riid_) AS howmany
FROM $b$ b
INNER JOIN $a$ a
ON b.riid_=a.riid_
GROUP BY a.storenumber) month_counts
FROM (
SELECT a.storenumber,
count (c.riid_) AS howmany
FROM $c$ c
INNER JOIN $a$ a
ON c.riid_=a.riid_
GROUP BY a.storenumber) new_counts
ON month_counts.storenumber = new_counts.storenumber) theend
where I'm at now:
SELECT howmanytotal AS total_counts_store
FROM (
SELECT Count (howmany) AS howmanytotal)
FROM (
SELECT month_counts.howmany,
new_counts.howmany)
FROM (
SELECT a.storenumber,
count (b.riid_) AS howmany
FROM $b$ b
inner join $a$ a
ON b.riid_=a.riid_
GROUP BY a.storenumber) month_counts
UNION
(
SELECT count (c.riid_) AS howmany
FROM $c$ c
inner join $a$ a
ON c.riid_=a.riid_
GROUP BY a.storenumber) new_counts
ON month_counts.storenumber = new_counts.storenumber) ORDER BY $a$.storenumber
Getting this error: Error: java.sql.SQLSyntaxErrorException: ORA-00923: FROM keyword not found where expected
Please correct SELECT statement:
Join the subqueries:
select
storenumber,
month_counts.howmany as month_count,
new_counts.howmany as new_count,
month_counts.howmany + new_counts.howmany as total_count
from (...) month_counts
join (...) new_counts using (storenumber)
order by storenumber;
If it is possible for a storenumber to be missing from one of the subquery results, then outer join and use COALESCE or NVL to deal with the nulls. Here is a query with a full outer join, which is not available in MySQL, but in Oracle and many other DBMS.
select
storenumber,
month_counts.howmany as month_count,
new_counts.howmany as new_count,
nvl(month_counts.howmany, 0) + nvl(new_counts.howmany, 0) as total_count
from (...) month_counts
full outer join (...) new_counts using (storenumber)
order by storenumber;
Ending up using sum and union to complete. Thank you for your help.
SELECT storenumber,
SUM(howmany) AS howmanytotal
FROM (SELECT a.storenumber,
Count (b.riid_) AS howmany
FROM $b$ b
inner join $a$ a
ON b.riid_ = a.riid_
GROUP BY a.storenumber
UNION
SELECT a.storenumber,
Count (c.riid_) AS howmany
FROM $c$ c
inner join $a$ a
ON c.riid_ = a.riid_
GROUP BY a.storenumber)
GROUP BY storenumber
ORDER BY storenumber
This gave me a list of store ids and how many active subscribers we have at each store (taken from two separate tables)

How can I unite these two related queries?

I have this query to check if a person is a customer or have been:
SELECT DISTINCT ON (person_id) person_id, person.name,
(CASE WHEN status = 'inactive' then 'Ex-Customer'
WHEN status = 'active' then 'Customer'
END) AS account_status
FROM person_subscription
INNER JOIN person ON person_subscription.person_id = person.id
ORDER BY person_id, status ASC
And I have this other query to get the locations:
SELECT person_id, string_agg(name, ';' ORDER BY person_id)
FROM person_location WHERE person_id IN
(SELECT person_id FROM person_subscription WHERE status IS NOT NULL)
GROUP BY person_id;
How can I unite them and show person location as a single row on the first query?
If I follow this correctly, you can use lateral joins:
select p.id as person_id, p.name, pl.*, ps.*
from person p
cross join lateral (
select string_agg(pl.name, ';' order by pl.name) as as person_locations
from person_location pl
where pl.person_id = p.id
) pl
cross join lateral (
select
case status
when 'inactive' then 'ex-customer'
when 'active' then 'customer'
end as account_status
from person_subscription ps
where ps.person_id = p.id
order by ps.??
limit 1
) ps
As commented already, your original first query is missing an order by clause, which makes it undefined which subscription status will be chosen where there are several matches. This translates as order by ps.?? in the second subquery, which you would need to replace with the relevant column name.
Another flaw, that time in the second query in your question, is that the order by clause of string_agg() is not deterministic (all rows in the group have the same person_id). I ordered by location name instead, you can change that to some other column if you like.
You would join it in:
SELECT DISTINCT ON (ps.person_id) ps.person_id, ps.person.name,
(CASE WHEN ps.status = 'inactive' then 'Ex-Customer'
WHEN ps.status = 'active' then 'Customer'
END) AS account_status
FROM person_subscription ps INNER JOIN
person p
ON ps.person_id = p.id LEFT JOIN
(SELECT pl.person_id, STRING_AGG(pl.name, ';') as names
FROM person_location pl
GROUP BY pl.person_id
) pl
ON pl.person_id = p.id
ORDER BY ps.person_id, p.status ASC;
I'm not sure what the significance of the WHERE clause is for getting locations, but you can include that in the subquery as well.

Count and group the number of times each town is listed in the table

SELECT PEOPLE.TOWNKEY, TOWN_LOOKUP.TOWN FROM PEOPLE
INNER JOIN TOWN_LOOKUP
ON PEOPLE.TOWNKEY = TOWN_LOOKUP.PK
ORDER BY TOWN
Current Table Output:
You are missing the group by clause entirely:
SELECT tl.town, COUNT(*)
FROM people p
INNER JOIN town_lookup ON p.townkey = tl.pk
GROUP BY tl.town
ORDER BY tl.town

SQL MAX() value across 2 or more queries

This seems like a basic action in SQL, but it has me stumped.
I have about 2 different subqueries, each grouped by LOCATION_ID that contain a date column. For example, one query includes a listing of WORKORDER records while another query pulls records from the NOTE table. Both of these queries includes a join to the LOCATION table allowing me to group by LOCATION_ID.
My goal is to pull the latest date of contact at that particular location and that can be in the form of a workorder, note date, followup date, etc. which are stored in different tables. So ideally I would have a query grouped by LOCATION_ID that shows the latest date of contact for that location.
I would post SQL but I don't have anything that is currently working for me. Any ideas on how to approach this type of scenario?
Thanks!
SELECT
L.LOCATION_ID, Max(MaxDate)
FROM
LOCATION AS L
LEFT JOIN
(SELECT
LOCATION_ID, Max(dbo.LeadNote.NoteDate) AS MaxDate
FROM
LeadNote
INNER JOIN
LOCATION ON LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
GROUP BY
LOCATION_ID) T1 ON L.LOCATION_ID = T1.CONTACTLOCATION_LOCATION_ID
LEFT JOIN
(SELECT
LOCATION_ID, Max(dbo.WORKORDER.WORKORDER_DATECREATED) AS MaxDate
FROM
WORKORDER
INNER JOIN
LOCATION ON LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY
LOCATION_ID) T2 ON L.LOCATION_ID = T2.CONTACTLOCATION_LOCATION_ID`
Perhaps you could try using UNION to get a single sql result, then wrap it and give it an alias, and then apply a MAX on the field you wish, which both queries return. Keep in mind that to use UNION both queries must return the same set of field names.
Ex:
Query A:
Select a, b, c from T1 where....
Query B:
Select a, f, e from T2 where...
you would have:
SELECT MAX(e)
FROM
(
(Select a, b, c, NULL as f, NULL as e from T1 where....)
UNION
(Select a, NULL as b, NULL as c, f, e from T2 where...)
) t
If you need to use a join you can use a case statement to fetch the larger date.
SELECT
L.LOCATION_ID,
(CASE WHEN(T2.MaxDate IS NULL OR T1.MaxDate > T2.MaxDate)
THEN T1.MaxDate
ELSE T2.MaxDate
END) MaxDate
...
Try:
SELECT
L.LOCATION_ID, Max(MaxDate)
FROM
(
(
SELECT
LOCATION_ID, Max(LeadNote.NoteDate) AS MaxDate
FROM
LeadNote
JOIN
LOCATION
ON
LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
GROUP BY
LOCATION_ID
)
UNION
(
SELECT
LOCATION_ID, Max(WORKORDER.WORKORDER_DATECREATED) AS MaxDate
FROM
WORKORDER
JOIN
LOCATION ON LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY
LOCATION_ID
)
)
It may need a little tweaking...but kudos to the comment by #DrCopyPaste if this works :)
You can do this with a simple join and a case statement:
SELECT
L.LOCATION_ID,
CASE WHEN(Max(LeadNote.NoteDate) IS NULL OR Max(LeadNote.NoteDate) > Max(WORKORDER.WORKORDER_DATECREATED)
THEN Max(LeadNote.NoteDate)
ELSE Max(WORKORDER.WORKORDER_DATECREATED) end AS maxDate
FROM
LOCATION AS L
LEFT JOIN LeadNote ON LeadNote.LOCATION_ID = LOCATION.LOCATION_ID
LEFT JOIN WORKORDER ON L.LOCATION_ID = WORKORDER_LOCATION_ID
GROUP BY L.LOCATION_ID