sql DISTINCT with COALESCE - sql

I am working with two tables in a database where the first table (T1) consist of measurements from a device and the other table (T2) has the information on each individual device.
In T2 there is a column called METADATA1 which could be a description, an empty string or null.
I would like to write a query that gets all the distinct devices that have measurements in T1 and their METADATA1. I want to replace the empty/null metadata with deviceid. Here is what I have
SELECT DISTINCT(t1.DEVICEID),
COALESCE(NULLIF(t2.METADATA1,''), t1.DEVICEID) AS METADATA1
FROM T1 t1 LEFT JOIN T2 t2 ON t1.DEVICEID = t2.DEVICEID
ORDER BY t1.DEVICEID ASC
This returns zero rows and does not work. If I replace the COALESCE with COALESCE(NULLIF(t2.METADATA1,''), '0') then I get the correct number of rows.
Could someone please tell me what I am doing wrong.

Your query should be returning rows, assuming t1 has rows. I would express it using GROUP BY rather than SELECT DISTINCT.
SELECT t1.DEVICEID,
COALESCE(NULLIF(MAX(t2.METADATA1), ''), t1.DEVICEID) AS METADATA1
FROM T1 t1 LEFT JOIN
T2 t2
ON t1.DEVICEID = t2.DEVICEID
GROUP BY t1.DEVICEID
ORDER BY t1.DEVICEID ASC;

Related

SQL query counts returns the same number

The following query:
Select t1.name
, t1.email
, t1.activated
, count(t2.id) as 'reporter'
, count(t3.id) as 'comments'
, count(t4.id) as 'reported'
from users t1
inner join tickets as t2 on t1.id = t2.reporter_id
inner join comments as t3 on t1.id = t3.user_id
inner join tickets as t4 on t1.id = t4.reported_id
group by name
The counts return all 3 the same number
It would be great to see sample data, current results and expect results.
But I'm guessing it's because your group by clause doesn't include the t1.email and t1.activated columns.
Select t1.name
, t1.email
, t1.activated
, count(t2.id) as 'reporter'
, count(t3.id) as 'comments'
, count(t4.id) as 'reported'
from users t1
inner join tickets as t2 on t1.id = t2.reporter_id
inner join comments as t3 on t1.id = t3.user_id
inner join tickets as t4 on t1.id = t4.reported_id
group by name
, t1.email
, t1.activated
Without sample data, it's hard to be sure, but I don't think your joins do what you want them to do. You will only get results for users who have are both "reported" and "reporter", and those tickets include at least 1 comment from the user who reported it.
count() returns the number of rows with non-NULL values. The ids are presumably NOT NULL so they return the same values.
The quick-and-dirty solution to your problem is to use COUNT(DISTINCT:
Select t1.name, t1.email, t1.activated,
count(distinct t2.id) as reporter,
count(distinct t3.id) as comments,
count(distinct t4.id) as reported
. . .
Do not use single quotes for column aliases! Only use single quotes for string and date constants.
Note that your query will never return 0 values for any of the counts. Also, this is more expensive than necessary. I am not providing a more efficient solution here, because the above answers your question. If you have other issues with the query, then ask a new question with appropriate sample data, desired results, and an explanation of what you want to do.

How to query the specific vales in columns form different tables(SQLite)?

I have two tables, table1 and table2. table1 has 'id' column. table2 has 'id' and 'quantity' columns. I want to compare the same values under 'id' columns from both tables and show the value under 'quantity' column form table2.
The simple logic is "select id=1 from table1 compare with select id=1 from table2, then show the quantity value from table2". Is there any way to query this statement?
Join the tables:
SELECT *
FROM
table1 t1
INNER JOIN table2 t2
ON t1.id = t2.id
Using INNER JOIN will cause the results to show only rows where the same ID is present in both tables. If you want to show all rows from table 1 and matching rows from table 2 plus blanks for any rows where there is no table 2 id for a particular table 1 id, then use LEFT JOIN instead of INNER JOIN.
If you only want certain columns in your output you can list them:
SELECT t1.id, t2.quantity
...
etc
More about joins - for future learning
In most other database systems there exists the corollary of LEFT join; RIGHT join. If you want all rows from table 2 plus matching rows from table 1, and blanks where there is no related table 1 row, use RIGHT JOIN. SQLite doesn't support RIGHT joins, so you'll have to rewrite your query (swap the table names around) so t2 is on the LEFT. It's the table name that matters, not the order of appearance in the ON section:
--all rows from t1 plus any matching rows from t2
SELECT *
FROM
table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.id
--all rows from t2 plus any matching rows from t1
SELECT *
FROM
table2 t2
LEFT JOIN table1 t1
ON t1.id = t2.id
Eventually you'll come across a FULL [OUTER] JOIN which is "all rows from t1 and any matching from t2, plus any additional rows from t2 and their possible matches from t1". SQLite doesn't support this either, but it can be emulated. Ordinarily it's emulated with a LEFT JOIN UNION RIGHT JOIN, but as SQLite doesn't support RIGHT, you'll have to emulate it with two LEFT joins, one with the tables swapped round:
--all rows from t1 plus any matching rows from t2
SELECT *
FROM
table1 t1
LEFT JOIN table2 t2
ON t1.id = t2.id
UNION
SELECT *
FROM
table2 t2
LEFT JOIN table1 t1
ON t1.id = t2.id
Cor. All that for the sake of being able to say this in e.g. SQLServer:
SELECT *
FROM
table1 t1
FULL OUTER JOIN table2 t2
ON t1.id = t2.id

Combine data from two tables into one output SQL

I have two tables, as below:
I'm hoping to create a view, where the result is as per the result above. That is, the Act column is the total of all matching records between tbl1 and tbl2.
Additional explaination, graphically:
I'd left join tbl1 with an aggregate query on tbl2:
SELECT t1.id, t1.req, COALESCE(t2.act, 0) AS act
FROM tbl1 AS t1
LEFT JOIN (SELECT id, SUM(act)
FROM tbl2
GROUP BY id) t2 ON t1.id = t2.id

SQL Joining three tables and using LEFT OUTER JOIN

I have three tables and two seperate SQL queries which are working correctly and I am having correct results.
If I try to join these three tables I am having null as result.
First query:
select T1.ID,T3.COMPANY
from T1,T3
where (T1.status!='CLOSED') and (T1.PRIORITY)>5 and T1.CLASSID=T3.CLASSID
Second query:
SELECT T1.ID, T2.DESCRIPTION
FROM T1
LEFT OUTER JOIN T2
ON T1.ID=T2.KEY
WHERE T1.status!='CLOSED'
AND (T2.CREATEDATE= (SELECT MAX(CREATEDATE)
FROM T2
WHERE T2.KEY=T1.ID))
I tried to join them but as result I am having null:
select T1.ID,T3.COMPANY,T2.DESCRIPTION
from T1
INNER JOIN T3 ON T1.CLASSID=T3.CLASSID
LEFT OUTER JOIN T2
ON T1.ID=T2.KEY
where (T1.status!='CLOSED') AND (T1.PRIORITY)>5
AND (T2.CREATEDATE= (SELECT MAX(CREATEDATE)
FROM T2
WHERE T2.KEY=T1.ID))
like it does not recognized last part for taking MAX value from T2 table.
What am I doing wrong? Thanks for help
Firstly, use an alias for the subquery on table T2.
T2.CREATEDATE =
(SELECT MAX(T2Alias.CREATEDATE)
FROM T2 AS T2Alias
WHERE T2Alias.KEY = T1.ID)
Secondly, consider moving this condition into the ON clause of the LEFT JOIN to table T2.
The first thing that jumps out at me is the new dependency on both T1.Priority > 5 and T2.CreateDate value being equal to the result of the inline query:
( AND (T1.PRIORITY) > 5
AND (T2.CREATEDATE =
(SELECT MAX(CREATEDATE) FROM T2 WHERE T2.KEY = T1.ID) )
Without the data it's difficult to check however this may be the issue

MySQL Join syntax for one to many relationship

I have a situation where I have one table of titles (t1) and another table with multiple links that reference these titles (t2) in a one to many relationship.
What I want is the full list of titles returned with a flag that indicates if there is a specific link associated with it.
Left Join and Group By:
SELECT
t1.id
, t1.title
, t2.link_id AS refId
FROM
t1
LEFT JOIN t2
ON (t1.id = t2.title_id)
GROUP BY t1.id;
This is close as it gives me either the first link_id or NULL in the refId column.
Now, how do I constrain the results if I have a specific link_id rather than allowing t2 run through the whole data set?
If I add a WHERE clause, for example:
WHERE t2.link_id = 123
I only get the few records where the link_id matches but I still need the full set of titles returned with NULL in the refId column unless link_id = 123.
Hope someone can help
Instead of in the WHERE clause, put your criteria in the LEFT JOIN clause:
SELECT
t1.id
, t1.title
, t2.link_id AS refId
FROM
t1
LEFT JOIN t2
ON t1.id = t2.title_id AND t2.link_id = 123
GROUP BY t1.id;
Put it in the join condition for the second table
SELECT t1.id, t1.title, t2.link_id as refId
FROM t1
LEFT JOIN t2 ON t1 = t2.title_id AND t2.link_id = 123
GROUP BY t1.id;