Why does this NOT IN query work as intended, but not this NOT EXISTS query? - sql

Working (NOT IN) retrieves 3 rows:
select DISTINCT d.* from Device d , Company c3
WHERE d.deviceid NOT IN
(
Select d1.deviceid from Device d1, Clone x1
WHERE d1.deviceid = x1.deviceID
AND
(
x1.XPath = 'hi'
OR x1.XPath = 'bye'
)
AND
(
EXISTS ( select * from (SELECT * FROM [dbo].[Split] ('T130SF0W2050', ',')) as s
WHERE x1.Value like '%' + s.items + '%' )
)
)
AND
d.companyid = c3.companyid and c3.companynumber in (SELECT * FROM [dbo].[Split] ('00223200', ','))
Not Working(not exists):
select DISTINCT d.* from Device d , Company c3
WHERE NOT EXISTS
(Select * from Device d1, Clone x1
WHERE d1.deviceid = x1.deviceID
AND
(
x1.XPath = 'hi'
OR x1.XPath = 'bye'
)
AND
(
EXISTS ( select * from (SELECT * FROM [dbo].[Split] ('T130SF0W2050', ',')) as s
WHERE x1.Value like '%' + s.items + '%' )
)
)
AND
d.companyid = c3.companyid and c3.companynumber in (SELECT * FROM [dbo].[Split] ('00223200', ','))
I'm unsure I'm using the exists syntax correct, what should I select from the subquery? I've tried a few different combinations. It won't run if I put WHERE d.deviceid NOT EXISTS
Solution (thanks to Nikola):
add AND d1.deviceid = d.deviceid inside the Exists subquery.

The difference is that the NOT IN query returns devices that match the company and don't match the inner query specification.
For the NOT EXIST query to work as written (where "work as written" refers to returning the same result as the top query), there can't be any devices that exist matching the inner query. If any devices match the inner query at all, the query won't return any results.

Related

Subqueries in Python

I am trying to use subqueries to run matching against multiple tables and move the unmatched records to new table.
I have written SQL subqueries but the only issue i am facing is the performace, it is taking lot of time to process.
create table UnmatchedRecord
(select a.*
from HashedValues a
where a.Address_Hash not in(select b.Address_Hash
from HashAddress b)
and a.Person_Hash not in(select d.Person_Hash
from HashPerson d)
and a.HH_Hash not in(select f.HH_Hash
from HashHH f)
and a.VehicleRegistration not in(select VehicleRegistration
from MasterReference)
and a.EmailAddress not in (select EmailAddress
from MasterReference)
and a.PhoneNumber not in (select PhoneNumber
from MasterReference)
and a.NationalInsuranceNo not in (select NationalInsuranceNo
from MasterReference))
You can at least replace four subqueries with one:
select HashedValues.*
from HashedValues
where not exists (
select *
from MasterReference
where HashedValues.VehicleRegistration = MasterReference.VehicleRegistration
or HashedValues.EmailAddress = MasterReference.EmailAddress
or HashedValues.PhoneNumber = MasterReference.PhoneNumber
or HashedValues.NationalInsuranceNo = MasterReference.NationalInsuranceNo
)
and not exists (
select *
from HashAddress
where HashedValues.Address_Hash = HashAddress.Address_Hash
)
and not exists (
select *
from HashPerson
where HashedValues.Person_Hash = HashPerson.Person_Hash
)
and not exists (
select *
from HashHH
where HashedValues.HH_Hash = HashHH.HH_Hash
)

sql - Update more rows than I expected

I'm trying to update a part of my table. If I do a select statement, I find 17 ocurrences, but when I update it, it updates 997 ocurrences. I only want to update the 17 ocurrences. This is my code:
update proc_try k set detail = (
select jobs from
(
with
a ( nameHost ) as (
select b.nameHost
from definition a ,schema.nodes b
where b.nameHost = a.idNode or b.nodeid=a.idNode
and nodetype not like 'R'
group by b.nameHost
having sum(1 + lengthb(nameJob)) - 1 > 4000
)
select nameHost, 'TOOLONG' as jobs
from a
UNION ALL
select p.nameHost, listagg(p.nameJob,',') within group (order by p.nameJob) as jobs
from
(
select distinct b.nameJob, a.nameHost
from definition b
right join schema.nodes a
on b.idNode in (a.nodeid,a.nameHost) and
b.application not like '#NOTINCLUDE'
where a.nameHost not in (select * from a) and nodetype not like 'R'
--b.application not like '#NOTINCLUDE'
) p
group by p.nameHost) random
where k.nameHost=random.nameHost);
Could you help me please?
You can generally convert a complex update into a merge:
merge into proc_try k
using
( select jobs
from ( with a(namehost) as
( select b.namehost
from definition a
join schema.nodes b
on b.namehost = a.idnode
or (b.nodeid = a.idnode and nodetype <> 'R')
group by b.namehost
having sum(1 + lengthb(namejob)) - 1 > 4000 )
select namehost
, 'TOOLONG' as jobs
from a
union all
select p.namehost
, listagg(p.namejob, ',') within group(order by p.namejob) as jobs
from ( select distinct
b.namejob, a.namehost
from schema.nodes a
left join definition b
on b.idnode in (a.nodeid, a.namehost)
and b.application not like '#NOTINCLUDE'
where a.namehost not in (select * from a)
and nodetype not like 'R'
) p
group by p.namehost
) random
) new_jobs
on (k.namehost = new_jobs.namehost)
when matched then update set k.detail = new_jobs.jobs;
This is untested as I don't have your tables or sample data.
Edit: Looks like we can simplify it a bit, to this:
merge into proc_try k
using
( with overlength (namehost) as
( select n.namehost
from definition d
join schema.nodes n
on n.namehost = d.idnode
or (n.nodeid = d.idnode and nodetype <> 'R')
group by n.namehost
having sum(1 + lengthb(n.namejob)) - 1 > 4000 )
select o.namehost, 'TOOLONG' as jobs
from overlength o
union all
select sd.namehost
, listagg(sd.namejob, ',') within group(order by sd.namejob) as jobs
from ( select distinct d.namejob, n.namehost
from schema.nodes n
left join definition d
on d.idnode in (n.nodeid, n.namehost)
and d.application not like '#NOTINCLUDE'
where n.namehost not in (select o.namehost from overlength o)
and n.nodetype not like 'R'
) sd
group by sd.namehost
) new_jobs
on (new_jobs.namehost = k.namehost)
when matched then update set k.detail = new_jobs.jobs;
I still can't see what
sum(1 + lengthb(namejob)) - 1
is meant to do, though. It looks like that could be simplified to
sum(lengthb(namejob))

Create view with with statement

How to create view with a with statement?
I'm getting on error on it:
WITH temp as (
select uu.email, u.logintime, u.region, p.id as panelid, p.panelname, p.numberofdownloads, dimensionType + ' (' + dimensionValue + ')' as filter
from stat_users u
left join stat_panels p
on u.id=p.sessionid
left join stat_filters f
on p.id=f.panelid
left join users uu
on uu.id=u.userid
where uu.Organization = 'name' AND
year(logintime) between 2015 and 2017
and panelname is not null
)
CREATE VIEW final as(
select aa.email, aa.logintime, aa.region, aa.panelname, aa.numberofdownloads as downloads, case when len(aa.filters) > 0 then left(aa.filters, len(aa.filters)-1) else '' end as filters
from (
Select distinct a.email, a.logintime, a.region, a.panelname, a.numberofdownloads,
(
Select b.filter + ', ' AS [text()]
From temp b
Where b.panelid=a.panelid
ORDER BY b.panelid
For XML PATH ('')
) filters
from temp a
) aa
)
I'm getting such error :
> Incorrect syntax near the keyword 'CREATE'. 'CREATE VIEW' must be the
> first statement in a query batch.
So, I need just to use Create view using select which based on WITH statement on Sql server 2014
Yes always the CREATE has to be the first statement in a query batch
CREATE VIEW vFinal AS
WITH Temp AS (
SELECT uu.email, u.logintime, u.region, p.id AS panelid, p.panelname, p.numberofdownloads, dimensionType + ' (' + dimensionValue + ')' AS Filter
FROM stat_users u
LEFT JOIN stat_panels p ON u.id=p.sessionid
LEFT JOIN stat_filters f ON p.id=f.panelid
LEFT JOIN users uu ON uu.id=u.userid
WHERE uu.Organization = 'name' AND
YEAR(logintime) BETWEEN 2015 AND 2017
AND panelname IS NOT NULL
)
SELECT aa.email, aa.logintime, aa.region, aa.panelname, aa.numberofdownloads AS downloads, CASE WHEN LEN(aa.filters) > 0 THEN LEFT(aa.filters, LEN(aa.filters)-1) else '' end as filters
FROM (
SELECT DISTINCT a.email, a.logintime, a.region, a.panelname, a.numberofdownloads,
(
SELECT b.filter + ', ' AS [text()]
FROM temp b
WHERE b.panelid=a.panelid
ORDER BY b.panelid
FOR XML PATH ('')
) filters
FROM temp a
) aa
GO
Syntax to create a view table using CTE
CREATE VIEW View_Name AS
WITH CTE_Name (Columns) AS (SELECT QUERY)
SELECT QUERY using the CTE Table
GO
The with clause is an optional prefix for select:
WITH query_name (column_name1, ...) AS
(SELECT ...)
SELECT ...
This is also true when with is used in a view:
CREATE VIEW ...
WITH ...
SELECT ...
;
See also: http://modern-sql.com/feature/with
CREATE or replace VIEW final as
select aa.email, aa.logintime, aa.region, aa.panelname, aa.numberofdownloads as downloads, case when len(aa.filters) > 0 then left(aa.filters, len(aa.filters)-1) else '' end as filters
from (
Select distinct a.email, a.logintime, a.region, a.panelname, a.numberofdownloads,
(
Select b.filter + ', ' AS [text()]
From temp b
Where b.panelid=a.panelid
ORDER BY b.panelid
For XML PATH ('')
) filters
from temp a )

Oracle sql join against extracted values

I am looking to reconcile data from 2 different tables where I need to carry out a concatenation and substr to create columns that I can use to carry out a match against.The following separate queries reflect the select statements from each table that produces the matching values that reflect sitenn.zonenn (e.g. site12.zone20) as nodename.
SELECT distinct(REGEXP_SUBSTR(B.NODE_NAME,'*site*.*')) as nodename
FROM OPC_ACT_MESSAGES A,OPC_NODE_NAMES B
WHERE A.MESSAGE_GROUP = 'Ebts_Status_Alarms'
AND A.SEVERITY <> 2
AND A.NODE_ID = B.NODE_ID;
SELECT 'site'||site_id||'.zone'||zone_id as nodename
FROM aw_active_alarms
GROUP BY site_id,zone_id;
I need to write a query that select all nodenames from one table that do not exist in the other.
Use left join to find it. It is faster than minus,not in,not exists etc.
SELECT a.nodename
FROM (SELECT DISTINCT( regexp_substr(B.node_name, '*site*.*') ) AS nodename
FROM opc_act_messages A,
opc_node_names B
WHERE A.message_group = 'Ebts_Status_Alarms'
AND A.severity <> 2
AND A.node_id = B.node_id
) a
LEFT JOIN
(SELECT 'site'
|| site_id
|| '.zone'
|| zone_id AS nodename
FROM aw_active_alarms
GROUP BY site_id,
zone_id
) b
ON a.nodename = b.nodename
WHERE b.nodename IS NULL
One simple way: use MINUS
SELECT distinct(REGEXP_SUBSTR(B.NODE_NAME,'*site*.*')) as nodename
FROM OPC_ACT_MESSAGES A,OPC_NODE_NAMES B
WHERE A.MESSAGE_GROUP = 'Ebts_Status_Alarms'
AND A.SEVERITY <> 2
AND A.NODE_ID = B.NODE_ID
MINUS
SELECT 'site'||site_id||'.zone'||zone_id as nodename
FROM aw_active_alarms
GROUP BY site_id,zone_id;
would this work?
WITH t1
AS (SELECT DISTINCT
(REGEXP_SUBSTR (B.NODE_NAME, '*site*.*')) AS nodename
FROM OPC_ACT_MESSAGES A, OPC_NODE_NAMES B
WHERE A.MESSAGE_GROUP = 'Ebts_Status_Alarms'
AND A.SEVERITY <> 2
AND A.NODE_ID = B.NODE_ID),
t2
AS ( SELECT 'site' || site_id || '.zone' || zone_id AS nodename
FROM aw_active_alarms
GROUP BY site_id, zone_id)
SELECT *
FROM t1
WHERE t1.nodename NOT IN (SELECT nodename FROM t2)

MySQL/SQL - When are the results of a sub-query avaliable?

Suppose I have this query
SELECT * FROM (
SELECT * FROM table_a
WHERE id > 10 )
AS a_results LEFT JOIN
(SELECT * from table_b
WHERE id IN
(SElECT id FROM a_results)
ON (a_results.id = b_results.id)
I would get the error "a_results is not a table". Anywhere I could use the re-use the results of the subquery?
Edit: It has been noted that this query doesn't make sense...it doesn't, yes. This is just to illustrate the question which I am asking; the 'real' query actually looks something like this:
SELECT SQL_CALC_FOUND_ROWS * FROM
( SELECT wp_pod_tbl_hotel . *
FROM wp_pod_tbl_hotel, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =12
AND wp_pod_rel.tbl_row_id =1
AND wp_pod.tbl_row_id = wp_pod_tbl_hotel.id
AND wp_pod_rel.pod_id = wp_pod.id
) as
found_hotel LEFT JOIN (
SELECT COUNT(*) as review_count, avg( (
location_rating + staff_performance_rating + condition_rating + room_comfort_rating + food_rating + value_rating
) /6 ) AS average_score, hotelid
FROM (
SELECT r. * , wp_pod_rel.tbl_row_id AS hotelid
FROM wp_pod_tbl_review r, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =11
AND wp_pod_rel.pod_id = wp_pod.id
AND r.id = wp_pod.tbl_row_id
AND wp_pod_rel.tbl_row_id
IN (
SELECT wp_pod_tbl_hotel .id
FROM wp_pod_tbl_hotel, wp_pod_rel, wp_pod
WHERE wp_pod_rel.field_id =12
AND wp_pod_rel.tbl_row_id =1
AND wp_pod.tbl_row_id = wp_pod_tbl_hotel.id
AND wp_pod_rel.pod_id = wp_pod.id
)
) AS hotel_reviews
GROUP BY hotel_reviews.hotelid
ORDER BY average_score DESC
AS sorted_hotel ON (id = sorted_hotel.hotelid)
As you can see, the sub-query which makes up the found_query table is repeated elsewhere downward as another sub-query, so I was hoping to re-use the results
You can not use a sub-query like this.
I'm not sure I understand your query, but wouldn't that be sufficient?
SELECT * FROM table_a a
LEFT JOIN table_b b ON ( b.id = a.id )
WHERE a.id > 10
It would return all rows from table_a where id > 10 and LEFT JOIN rows from table_b where id matches.