I have two tables with one to many relation, like this:
MY_TABLE(ID, VALUE)
MY_TABLE_ATTRIBUTE(ID, MY_TABLE_ID, NAME, VALUE)
I want to check if there is record in MY_TABLE with particular attributes.
This query will probably explain what I am doing:
select 1
from MY_TABLE mt
where exists (select 1
from MY_TABLE_ATTRIBUTE mta
where mta.my_table_id = mt.id
and (mta.name = 'attributeName1' and mta.value = 'attributeValue1'))
and exists (select 1
from MY_TABLE_ATTRIBUTE mta
where mta.my_table_id = mt.id
and (mta.name = 'attributeName2' and mta.value = 'attributeValue2'))
and exists ...
.
.
.
My question is if there is a better (faster) way to check that existence.
Thanks in advance
Your query is fine. For performance, you want the following index:
create index idx_my_table_attribute_3 on my_table_attribute(my_table_id, name, value);
In fact, with this index, your code is probably the fastest way to implement this logic in Oracle.
Try the following rewrites:
select * from MY_TABLE mt
where exists (select 1 from MY_TABLE_ATTRIBUTE mta
where mta.my_table_id = mt.id
and(
(mta.name = 'attributeName1' and mta.value = 'attributeValue1')
OR (mta.name = 'attributeName2' and mta.value = 'attributeValue2')
OR ....
)
or
select * from MY_TABLE mt
where mt.id in (select mta.my_table_id from MY_TABLE_ATTRIBUTE mta
where
(mta.name = 'attributeName1' and mta.value = 'attributeValue1')
OR (mta.name = 'attributeName2' and mta.value = 'attributeValue2')
OR ....
)
An index on (name,value) may help if the cardinality of these columns is very high.
Related
I am having quite a struggle with the presented postgres request.
I have a table objects with a few columns, including an id column.
I have a table object_couples that references couples of objects with id. This table contains in consequence 2 columns of ids.
I have an external variable, like int external_variable = 42.
I am trying to select every entry of the objects table where the id of the selected object and the id of the external_variable does not exist as a couple in the object_couples table.
My request looks like the following :
SELECT id, c1, c2
FROM objects
WHERE condition1 AND condition2
EXCEPT SELECT left_id, right_id
FROM object_couples
WHERE objects.id != object_couples.left_id
AND external_variable != object_couples.right_id;
What can I do?
EDIT 1 :
The following request is not rejected but causes in pycharm a code 137(SIGKILL) :
SELECT id, c1, c2
FROM objects AS S
INNER JOIN object_couples
ON object_couples.left_id != S.id
AND object_couples.right_id != external_variable
WHERE S.c1 > 1234 AND S.c2 < 5678```
I am thinking not exists:
select o.*
from objects o
where not exists (select 1
from object_couples oc
where (oc.id = oc.left and 42 = oc.right) or
(oc.id = oc.right and 42 = oc.left)
);
For performance, you might find that this works better:
select o.*
from objects o
where not exists (select 1
from object_couples oc
where oc.id = oc.left and 42 = oc.right
) and
not exists (select 1
from object_couples oc
where oc.id = oc.right and 42 = oc.left
);
In particular if you have indexes on object_couples(left, right) and object_couples(right, left) then this might even be fast.
I am using the below query to update one column based on the conditions it is specified. I am using "inner join" but it is taking more than 15 seconds to run the query even if it has to update no records(0 records).
UPDATE CONFIGURATION_LIST
SET DUPLICATE_SERIAL_NUM = 0
FROM CONFIGURATION_LIST
INNER JOIN (SELECT DISTINCT APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER, COUNT(*) AS NB
FROM CONFIGURATION_LIST
WHERE
PLANT = '0067'
AND APPLIED_SERIAL_NUMBER IS NOT NULL
AND APPLIED_SERIAL_NUMBER !=''
AND DUPLICATE_SERIAL_NUM = 1
GROUP BY
APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER
HAVING
COUNT(*) = 1) T2 ON T2.APPLIED_SERIAL_NUMBER = CONFIGURATION_LIST.APPLIED_SERIAL_NUMBER
AND T2.APPLIED_MAT_CODE = CONFIGURATION_LIST.APPLIED_MAT_CODE
WHERE
CONFIGURATION_LIST.PLANT = '0067'
AND DUPLICATE_SERIAL_NUM = 1
The index is there with APPLIED_SERIAL_NUMBER and APPLIED_MAT_CODE and fragmentation is also fine.
Could you please help me on the above query performance.
First, you don't need the DISTINCT when using GROUP BY. SQL Server probably ignores it, but it is a bad idea anyway:
UPDATE CONFIGURATION_LIST
SET DUPLICATE_SERIAL_NUM = 0
FROM CONFIGURATION_LIST INNER JOIN
(SELECT APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER, COUNT(*) AS NB
FROM CONFIGURATION_LIST cl
WHERE cl.PLANT = '0067' AND
cl.APPLIED_SERIAL_NUMBER IS NOT NULL AND
cl.APPLIED_SERIAL_NUMBER <> ''
cl.DUPLICATE_SERIAL_NUM = 1
GROUP BY cl.APPLIED_MAT_CODE, cl.APPLIED_SERIAL_NUMBER
HAVING COUNT(*) = 1
) T2
ON T2.APPLIED_SERIAL_NUMBER = CONFIGURATION_LIST.APPLIED_SERIAL_NUMBER AND
T2.APPLIED_MAT_CODE = CONFIGURATION_LIST.APPLIED_MAT_CODE
WHERE CONFIGURATION_LIST.PLANT = '0067' AND
DUPLICATE_SERIAL_NUM = 1;
For this query, you want the following index: CONFIGURATION_LIST(PLANT, DUPLICATE_SERIAL_NUM, APPLIED_SERIAL_NUMBER, APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER).
The HAVING COUNT(*) = 1 suggests that you might really want NOT EXISTS (which would normally be faster). But you don't really explain what the query is supposed to be doing, you only say that this code is slow.
Looks like you're checking the table for rows that exist in the same table with the same values, and if not, update the duplicate column to zero. If your table has a unique key (identity field or composite key), you could do something like this:
UPDATE C
SET C.DUPLICATE_SERIAL_NUM = 0
FROM
CONFIGURATION_LIST C
where
not exists (
select
1
FROM
CONFIGURATION_LIST C2
where
C2.APPLIED_SERIAL_NUMBER = C.APPLIED_SERIAL_NUMBER and
C2.APPLIED_MAT_CODE = C.APPLIED_MAT_CODE and
C2.UNIQUE_KEY_HERE != C.UNIQUE_KEY_HERE
) and
C.PLANT = '0067' and
C.DUPLICATE_SERIAL_NUM = 1
I will try with a select first:
select APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER, count(*) as n
from CONFIGURATION_LIST cl
where
cl.PLANT='0067' and
cl.APPLIED_SERIAL_NUMBER IS NOT NULL and
cl.APPLIED_SERIAL_NUMBER <> ''
group by APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER;
How many rows do you get with this and how long does it take?
If you remove your DUPLICATE_SERIAL_NUM column from your table it might be very simple. The DUPLICATE_SERIAL_NUM suggests that you are searching for duplicates. As you count your rows you could introduce a simple table that contains the counts:
create table CLCOUNT ( N int unsigned, C int /* or what APPLIED_MAT_CODE is */, S int /* or what APPLIED_SERIAL_NUMBER is */, PLANT char(20) /* or what PLANT is */, index unique (C,S,PLANT), index(PLANT,N));
insert into CLCOUNT select count(*), cl.APPLIED_MAT_CODE, cl.APPLIED_SERIAL_NUMBER, cl.PLANT
from CONFIGURATION_LIST cl
where
cl.PLANT='0067' and
cl.APPLIED_SERIAL_NUMBER IS NOT NULL and
cl.APPLIED_SERIAL_NUMBER <> ''
group by APPLIED_MAT_CODE, APPLIED_SERIAL_NUMBER;
How long does this take?
Now you can simply select * from CLCOUNT where PLANT='0067' and N=1;
This is all far from being perfect. But you should be able to analyze (EXPLAIN SELECT ...) your queries and find why it takes so long.
I have 3 tables I am using to compare data and find where a record may be missing from one of the tables. The tables are A_Client, A_USER_Defined and A_Group_Member.
A_CLIENT contains: ClientName, ClientUID
A_USER_Defined contains: ClientUID, LOB
A_GROUP_MEMBER contains: ID, ClientUID
So the common column in each is ClientUID.
I am trying to find the Device(s) where defined.lob = 'value1' and does not exist in the member table where member.id = 'value2'
So far my searches comes up empty and am guessing it's something to do with the different joins? Here is the query I am using:
SELECT A_CLIENT.ClientName
, A_CLIENT.ClientUID
, A_USER_DEFINED.LOB
FROM A_CLIENT
INNER JOIN
A_USER_DEFINED ON A_CLIENT.ClientUID = A_USER_DEFINED.ClientUID
WHERE A_USER_DEFINED.LOB = 'value1'
AND NOT EXISTS (
SELECT ClientUID
FROM A_GROUP_MEMBER
WHERE GroupID = 'value2'
)
Any help would be greatly appreciated.
Thank you.
select cli.ClientName, cli.ClientUID, def.LOB
from A_CLIENT cli
inner join A_USER_DEFINED def on def.ClientGUID = cli.ClientGUID and def.LOB = 'value1'
left join A_GROUP_MEMBER grp on grp.ClientUID = cli.ClientUID and mbr.ID = 'value2'
where mbr.UID is null
select cli.ClientName, cli.ClientUID, def.LOB
from A_CLIENT cli, A_USER_DEFINED def
where def.ClientGUID = cli.ClientGUID and def.LOB = 'value1'
and cli.ClientUID not in (select ClientUID from A_GROUP_MEMBER where GroupID = 'value2')
and various other possibilities, depending on what type of join or predicate your engine is more comfortable with
Edit: the question and the table/field names changed considerably since I posted my answer. They seem to have settled down now and so I changed my code to suit.
Note: the EXISTS predicate in your query only checks whether are any records at all with ID = 'value2'; it should quite probably check only for records that also have a matching UID.
Also, there seems to be some confusion potential between ClientUID and ClientGUID. Is that a typo or does your DB actually have both names in it? If it is the latter then someone is in dire need of being educated with a blunt instrument.
select devices.*
from devices
left join member
on devices.ClientUID = member.ClientUID
and devices.lob = 'value1'
and member.id = 'value2'
where member.ClientUID is null
I think you are actually quite close and just need to correlate the not the exists subquery. Without sample data I haven't tested, but I think that minimal correction will fix your query.
SELECT A_CLIENT.ClientName
, A_CLIENT.ClientUID
, A_USER_DEFINED.LOB
FROM A_CLIENT
INNER JOIN
A_USER_DEFINED ON A_CLIENT.ClientUID = A_USER_DEFINED.ClientUID
WHERE A_USER_DEFINED.LOB = 'value1'
AND NOT EXISTS (
SELECT ClientUID
FROM A_GROUP_MEMBER
WHERE A_GROUP_MEMBER.ClientUID = A_CLIENT.ClientUID
AND GroupID = 'value2'
)
I'd probably use some table alias ti make that easier to read but ymmv:
SELECT c.ClientName
, c.ClientUID
, u.LOB
FROM A_CLIENT c
INNER JOIN
A_USER_DEFINED u ON c.ClientUID = u.ClientUID
WHERE A_USER_DEFINED.LOB = 'value1'
AND NOT EXISTS (
SELECT 1
FROM A_GROUP_MEMBER g
WHERE g.ClientUID = c.ClientUID
AND GroupID = 'value2'
)
I have an SQL query which can have around 1.5k of IDs OR'ed in the following form. They are the IDs of people I have and they are individually selectable, hence the many ORs when everyone is selected. Is it better to just SELECT everyone's ID then put it in the AND condition, UNION instead of OR, or perhaps use IN to bunch up all IDs, since the user may select everyone accept 1 person. Thanks.
...
AND (
(UserID = '53b95690-22d8-44a2-ad56-919cb4037218')
OR (UserID = '87b7fc0c-28f4-4f2e-9909-066df42245fa')
OR (UserID = '98c1b5e3-6ba5-4bd9-b8f5-d3b2221e3e3a')
OR...
EDIT: The complete query, as requested;
SELECT *
FROM Mail WITH (NOLOCK)
WHERE Active= 1
AND Company= '1d034e8b-0122-4531-8795-895d9287920f'
AND (
CompanyDivisionID= '129bcca1-b1d8-4a9e-8152-0b9e936c9d01'
OR CompanyDivisionID= '1bf4023d-22a3-4520-b751-7842576f42b7'
)
AND (
(DestinationUserID = '53b95690-22d8-44a2-ad56-919cb4037218')
OR (DestinationUserID = '87b7fc0c-28f4-4f2e-9909-066df42245fa')
OR (DestinationUserID = '98c1b5e3-6ba5-4bd9-b8f5-d3b2221e3e3a')
...
...
...
OR (DestinationUserID = '8c78fc05-7969-48fd-9b30-774e5d9a70bd')
OR (DestinationUserID = 'e7b76096-fe7d-44b8-9158-8293ac609471')
OR (DestinationUserID = '8a6b7385-4339-43fb-b95b-a7b687982bcd')
)
ORDER BY SendingDate DESC
Create a (temporary) table containing your selected UserIDs and join to that table.
SELECT *
FROM Mail WITH (NOLOCK)
inner join SelectedUsers on mail.DestinationUserID = SelectedUsers.UserID
WHERE Active= 1
SELECT *
FROM myTable m
WHERE m.userId = :userId
AND m.X = (SELECT MAX(X)
FROM myTable m
WHERE m.userId = :userId
AND m.contactNumber = :contactNumber)";
The problem is,second part of statement evaluates to null in case no such row is present and the statement fails to execute.I want the result to be empty in such a case.
One way to solve this problem is to do expensive filesort(order by) and then fetch the required field at code level. Any better solution to this problem ?
Can you use ISNULL?
and m.X = ISNULL(, '')
I'm not sure why you're getting NULLs here, but try this:
SELECT myTable.*, IF myTableMax.myMaxX IS NOT NULL myTableMax.myMaxX ELSE ""
FROM myTable
LEFT OUTER JOIN
(SELECT userID, contactNumber, MAX(X) AS myMaxX
FROM myTable
GROUP BY userID, contactNumber) AS myTableMax
ON myTable.userID = myTableMax.userID
AND myTable.contactNumber = myTableMax.contactNumber
WHERE myTable.userID = :userID
AND myTable.contactNumber = :contactNumber
If you're concerned about performance, add an index on mytable (userID, contactNumber).