Nested SQL query searching the wrong table (postgreSQL) - sql

I have two tables:
devices : (id (int), type(int))
devices_log : (id (int), device_id (int) (FK), data(string), date(string))
The type is a number between 1 and 10, the data column should be a number between 1 and 100 ("1", ..., "100") or "emptyX" (the X represents any character from "a" to "z")
The device which has the type 9 always has a number in the data column.
I need to update the data field for all the "type 9" devices which
have a data bigger than 50 so that ==> data = data /2.
I've started with an INNER JOIN :
select l.id
from devices_log l
inner join (select id from devices where type = 9) d on (l.device_id = d.id)
This statement returns all the logs for "type 9" devices, but when I add the where condition :
select l.id
from devices_log l
inner join (select id from devices where type = 9) d on (l.device_id = d.id)
where cast(data as INTEGER) > 50
I got this error :
ERROR: invalid input syntax for integer: "emptyG"
I've also tried so many statements that lead to the same error :
select id
from devices_log
where device_id in (select id from devices where type = 9)
and cast(data as integer) > 50
select id from
(
select id, device_id, cast (devices_log.data as integer) as int_data
from devices_log
join devices on (devices_log.device_id = devices.id
) and type = 9) ccs where ccs.int_data > 50
Any suggestions?
Thanks in advance

SQL queries describe the result set, not the specific steps being taken. I actually thought this problem didn't appear in Postgres (I've seen it in other databases). I would start with this version:
select l.id
from devices_log l inner join
devices d
on l.device_id = d.id
where d.type = 9 and cast(l.data as INTEGER) > 50 ;
If this doesn't fix the problem, then you can fix this with a case in the where:
select l.id
from devices_log l inner join
devices d
on l.device_id = d.id
where d.type = 9 and
(case when d.type = 9 then cast(l.data as INTEGER) end) > 50 ;
The case should not evaluate the then unless the condition is true.

Related

sqlite return same value on left join

in below my sqlite command i want to get count of barcoeds when that's equals with sessions.id
select sessions.id, sessions.session_name, sessions.session_type,sessions.date_time, count(barcodes.id) as barcode_count
from sessions left join barcodes
on sessions.id = barcodes.session_id
group by barcodes.id
order by sessions.id desc
this command works, but that return more data with same value, for example if data is one, that return more than 3, but really i have one row
0 = {_List} size = 5
0 = 11
1 = "111"
2 = 2
3 = "1398/05/14 ساعت: 08:43"
4 = 1
1 = {_List} size = 5
0 = 11
1 = "111"
2 = 2
3 = "1398/05/14 ساعت: 08:43"
4 = 1
2 = {_List} size = 5
0 = 11
1 = "111"
2 = 2
3 = "1398/05/14 ساعت: 08:43"
4 = 1
I think you want one row per session. So, your query is aggregating by the wrong column:
select s.id, s.session_name, s.session_type,
s.date_time, count(b.id) as barcode_count
from sessions s left join
barcodes b
on s.id = b.session_id
group by s.id
---------^ sessions not barcode
order by s.id desc;
You might find this also easy to do with a correlated subquery:
select s.*,
(select count(*) from barcodes b where b.session_id = s.id)
from sessions s;
The use of table aliases in these queries makes them easier to write and to read.
First count the ids for each session_id in table barcodes and then join to sessions:
select
s.id, s.session_name, s.session_type, s.date_time,
coalesce(b.barcode_count, 0) barcode_count
from sessions s left join (
select session_id, count(id) barcode_count
from barcodes
group by session_id
) b on s.id = b.session_id
order by s.id desc
I guess id is unique in the table barcodes so there is no need for count(distinct id).

SQL server join issue

i have the following statement in a stored procedure that is returning strange results. Given two columns where one (RL) is less than 0 e.g -2, it should add 2 to another column (HD). If the negative value was -8 it should add 8 to the HD column.
In a test ive just done, the RL column had 0 and HD was 2. I changed the RL to -2 and run the code. I was EXPECTING : RL = 0 and HD = 4. INSTEAD the RESULT was RL = 0 and HD = 5.
I think the problem is due to the presence of the join. How would i write this to replace the join with a WHERE clause please.
UPDATE P
SET P.HD = P.HD + P.RL
,P.RL = 0
FROM Products P
INNER JOIN (
SELECT id
,RL
FROM Products
WHERE id IN (
SELECT ProductID
FROM OrderDetails
WHERE OrderID = #OrderId
)
AND RL < 0
) Q ON P.ID = Q.id
cheers
Try this one -
UPDATE Products
SET HD = HD + RL,
RL = 0
FROM P
WHERE RL < 0
AND ID IN (
SELECT ProductID
FROM dbo.OrderDetails
WHERE OrderID = #OrderId
)
Small check -
DECLARE #t TABLE (a INT, b INT)
INSERT INTO #t (a, b)
VALUES (1, 2)
UPDATE #t
SET a = b, b = 0
SELECT * FROM #t

How to get the actual values from a SQL join table

I have two tables [dbo].Notifications and [dbo].ClientsNotifications where :
[dbo].Notifications:
ID : Notification
1 : 'Notification1'
2 : 'Notification2'
3 : 'Notification3'
and so on...
and
[dbo].ClientsNotifications:
Id : ClientId : NotificationId
1 : 1 : 1
2 : 2 : 2
3 : 1 : 3
4 : 5 : 2
and so on..
What I want is by given ClientId to fetch all the string values from [dbo].Notifications.SELECT *
I tried something like this :
FROM [dbo].Notifications c, [dbo].ClientsNotifications a
WHERE a.ClientId IN (
SELECT c.Notification
FROM [dbo].ClientsNotifications a2, [dbo].Notifications c2
WHERE a2.ClientId = 1
)
but it gives me this error :
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value 'Notification1' to data type int.
I'm not very experienced in SQL so I'm not certain that this is even the right way (query) to fetch this data. At the end I want to get all string value notifications for user so I can show them in the view.
Use this:
select n.Notification
from Notifications n
where n.Id in
( select cn.NotificationId
from ClientNotifications cn
where cn.ClientId = 1
)
It selects all notifications where there is a matching record in ClientNotifications. There is no need for a join since you only wish the Notification field. If you do need values from that other table, use this:
select n.Notification
, cn.ClientId /* some fields from ClientNotifications */
from Notifications n
join ClientNotifications cn
on n.Id = cn.NotificationId
where cn.ClientId = 1
Your code is trying to grab the ClientID from a list of Notification messages. Try:
SELECT Notification
FROM Notifications
JOIN ClientsNotifications
ON Notifications.ClientId = ClientsNotifications.ClientId
WHERE ClientId = 1
You are selecting notifincation strings in the subquery and try to fetch the records where the client id is the same as the notification string. That doesn't only compare data of different type (hence the error), it also compares values that has nothing to do with each other.
You should use a join in the query rather than a subquery:
select
c.Notification
from
[dbo].ClientsNotifications a
inner join [dbo].Notifications c on c.ID = a.NotificationId
where
a.ClientId = 1
Your subquery will return varchar (Notification1, Notification2 or Notification3) :
SELECT c.Notification
FROM [dbo].ClientsNotifications a2, [dbo].Notifications c2
WHERE a2.ClientId = 1
I assume you just change your subquery to make it works
SELECT c.ID
FROM [dbo].ClientsNotifications a2, [dbo].Notifications c2
WHERE a2.ClientId = 1
Try this:
SELECT n.Notification -- The text of the notification record
FROM [dbo].Notifications n
INNER JOIN [dbo].ClientsNotifications cn -- join Notifications table to ClientNotifications table
ON n.Id = cn.NotificationId -- when Notification.Id matches ClientNotification.NotificationId
WHERE cn.ClientId = 1 -- where ClientId = 1
Using an inner join should be more efficient than using a subquery.

How to find rows that have one equal value and one different value from the table

I have the following table:
ID Number Revision
x y 0
x y 1
z w 0
a w 0
a w 1
b m 0
b m 0
I need to return rows that for the same Number thare are more then one ID with the same Revision.Number can be "Null" and I don't need those values.
The output should be:
z w 0
a w 0
I have tried the following query:
SELECT a.id,a.number,a.revision,
FROM table a INNER JOIN
(SELECT id, number, revision FROM table where number > '0'
GROUP BY number HAVING COUNT(*) > 1
) b ON a.revision = b.revision AND a.id != b.id
A little addition- I have rows in my table with the same Number, ID and Revision- I don't need those rows in my query to be displayed!
It is not working! Please help me to figure out how to fix it.
Thanks.
Select t.Id,s.number,t.revision
from (Select number,count(*) 'c'
from table t1
where revision=0
group by number
having count(*) > 1
) s join table t on t.number= s.number
where revision = 0
Another simple approach:
SELECT DISTINCT b.id, b.Number, b.Revision
FROM tbl a
INNER JOIN tbl b
ON a.ID != b.ID AND a.Number = b.Number AND a.Revision = b.Revision;
This is tested in MySql 5, syntax might differ slightly.
You are not that far away with your query:
SELECT a.id,a.number,a.revision
FROM table a
JOIN (
-- multiple id for the same number and revision
SELECT number, revision
FROM table
GROUP BY number, revision
HAVING COUNT(*) > 1
) b
ON a.revision = b.revision
AND a.number = b.number
Untested, but you should get the idea. If your sql-server is a resent version you can solve this with OLAP functions as well.
To filter out rows where the whole row is duplicated we can select only unique rows via group by and having:
SELECT a.id,a.number,a.revision
FROM table a
JOIN (
-- multiple id for the same number and revision
SELECT number, revision
FROM table
GROUP BY number, revision
HAVING COUNT(*) > 1
) b
ON a.revision = b.revision
AND a.number = b.number
GROUP BY a.id,a.number,a.revision
HAVING COUNT(1) = 1

How to create a subset query in sql?

I have two tables as follows:
CREATE List (
id INTEGER,
type INTEGER REFERENCES Types(id),
data TEXT,
PRIMARY_KEY(id, type)
);
CREATE Types (
id INTEGER PRIMARY KEY,
name TEXT
);
Now I want to create a query that determines all ids of List which has given type strings.
For example,
List:
1 0 "Some text"
1 1 "Moar text"
2 0 "Foo"
3 1 "Bar"
3 2 "BarBaz"
4 0 "Baz"
4 1 "FooBar"
4 2 "FooBarBaz"
Types:
0 "Key1"
1 "Key2"
2 "Key3"
Given the input "Key1", "Key2", the query should return 1, 4.
Given the input "Key2", "Key3", the query should return 3, 4.
Given the input "Key2", the query should return 1, 3, 4.
Thanks!
select distinct l.id
from list l
inner join types t on t.id = l.type
where t.name in ('key1', 'key2')
group by l.id
having count(distinct t.id) = 2
You have to adjust the having clause to the number of keys you are putting in your where clause. Example for just one key:
select distinct l.id
from list l
inner join types t on t.id = l.type
where t.name in ('key2')
group by l.id
having count(distinct t.id) = 1
SQlFiddle example
You can use the following trick to extend Jurgen's idea:
with keys as (
select distinct t.id
from types t
where t.name in ('key1', 'key2')
)
select l.id
from list l join
keys k
on l.type = keys.id cross join
(select count(*) as keycnt from keys) k
group by l.id
having count(t.id) = max(k.keycnt)
That is, calculate the matching keys in a subquery, and then use this for the counts. This way, you only have to change one line to put in key values, and you can have as many keys as you would like. (Just as a note, I haven't tested this SQL so I apologize for any syntax errors.)
If you can dynamically produce the SQL, this may be one of the most efficent ways, in many DBMS:
SELECT l.id
FROM List l
JOIN Types t1 ON t1.id = l.type
JOIN Types t2 ON t2.id = l.type
WHERE t1.name = 'Key1'
AND t2.name = 'Key2' ;
See this similar question, with more than 10 ways to get the same result, plus some benchmarks (for Postgres): How to filter SQL results in a has-many-through relation