So this has been bothering me for some time because I feel like in MSSQL this query would run just fine but at my new job I am forced to use Oracle. I have a subselect in a query where I want to find all of the people not assigned to a survey. My query is as follows:
Select distinct * From GetAllUsers, getperms
Where id not in (getperms.users) and Survey_ID = '1'
If there are three users in the getperms table I get three rows for each person in the the GETALLUsers table.
I guess I could do some kind of join and that's no problem, it's just really bothering me that this doesn't work when i think that it should.
I feel like in MSSQL this query would run just fine
It would not. In both Oracle and MS-SQL, an IN clause needs to be a static list of items or a subquery that returns one column, so you'd need something like:
Select distinct *
From GetAllUsers
Where id not in (SELECT id FROM getperms.users)
and Survey_ID = '1'
Note that I took getperms out of the FROM since it produces a cross-join, which is why you get every combination of records from both tables.
Your query looks just horrible. First of all you are using a join syntax that has become out of date more than twenty years ago. Then you are using NOT IN where it doesn't make sense (your set contains just one value). Then I can hardly imagine that DISTINCT makes sense in your query. Or one of the two tables contains records that are exact duplicates, which it shouldn't. Is Survey_ID really a string? And as you are working with two tables, you should use qualifiers on your columns to indicate where they reside in, e.g. GetAllUsers.id. I assume that Survey_ID resides in getperms.
Your query properly written looks thus:
Select *
From GetAllUsers gau
Join getperms gp On gp.Survey_ID = '1' And gp.users <> gau.id;
But of course whether you write it this way or the other, it does exactly the same. And there is no difference whether you use it in Oracle or SQL Server. What is does is: get all combinations of GetAllUsers and survey-1 getperms, except for the matches. So every user will be in the results, each combined with almost every getperms record.
You say: "I want to find all of the people not assigned to a survey". That would rather be:
Select *
From GetAllUsers
Where id Not In (Select users From getperms Where Survey_ID = '1');
You can use any of the following 3 methods,if you wanted to exclude the getperms users from GetAllUSers .
SELECT DISTINCT a.*
FROM GetAllUsers a
LEFT JOIN getperms b
ON a.id=b.users
WHERE b.users is null AND Survey_ID = '1'
OR
SELECT DISTINCT *
FROM GetAllUsers a
WHERE NOT EXISTS (SELECT 1
FROM getperms b
WHERE a.id=b.users)
AND Survey_ID = '1'
OR
SELECT DISTINCT *
FROM GetAllUsers
WHERE ID NOT IN (SELECT users
FROM getperms )
AND Survey_ID = '1'
Related
I have two tables (PlayerDTO and ClubDTO) and am using a JOIN to fetch data as follows:
SELECT * FROM PlayerDTO AS pl
INNER JOIN ClubDTO AS cl
ON pl.currentClub = cl.id
WHERE cl.nation = 7
This returns the correct rows from PlayerDTO, but in every row the id column has been changed to the value of the currentClub column (eg instead of pl.id 3,456 | pl.currentClub 97, it has become pl.id 97 | pl.currentClub 97).
So I tried the query listing all the columns by name instead of Select *:
SELECT pl.id, pl.nationality, pl.currentClub, pl.status, pl.lastName FROM PlayerDTO AS pl
INNER JOIN ClubDTO AS cl
ON pl.currentClub = cl.id
WHERE cl.nation = 7
This works correctly and doesn’t change any values.
PlayerDTO has over 100 columns (I didn’t list them all above for brevity, but I included them all in the query) but obviously I don’t want to write every column name in every query.
So could somebody please explain why Select * changes the id value and what I need to do to make it work correctly? All my tables have a column called id, is that something to do with it?
SELECT *... is, according to the docs...
shorthand for “select all columns.” (Source: Dev.MySQL.com
Both your tables have id columns, so which should be returned? It's not indicated, so MySQL makes a guess. So select what you want to select...
SELECT pl.id, *otherfieldsyouwant* FROM PlayerDTO AS pl...
Or...
SELECT pl.* FROM PlayerDTO AS pl...
Typically, SELECT * is bad form. The odds you are using every field is astronomically low. And the more data you pull, the slower it is.
This my scenario I tried to search a record in the SQL table using the name. So, I tried to create a subquery and I used like operator also in Postgres. SQL query It's working fine. but it's taking so much time. So, I checked why it's taking so much time. the reason is the subquery. In the subquery it hitting all the records in the table. How to optimize subquery.
SQL QUery
SELECT
id, latitude,longitude,first_name,last_name,
contact_company_id,address,address2,city,state_id, zip,country_id,default_phone_id,last_contacted,image,contact_type_id
FROM contact
WHERE company_id = 001
AND contact_company_id IN (select id from contactcompany where lower( name ) ~*'jack')
So, I tried to run this query it's taking 2 seconds and it hit all records in the contact company table that only It's takes time.
How to optimize subquery using SQL?
Please try a sub query as a inner join with a main table, both query give same result.
Example here :
SELECT contact.id,
contact.latitude,
contact.longitude,
contact.first_name,
contact.last_name,
contact.contact_company_id,
contact.address,
contact.address2,
contact.city,
contact.state_id,
contact.zip,
contact.country_id,
contact.default_phone_id,
contact.last_contacted,
contact.image,
contact.contact_type_id
FROM contact As contact
Inner Join contactcompany As contactcompany On contactcompany.id = contact_company_id
WHERE company_id = 001
AND lower( name ) ~*'jack'
I would start by writing the query using exists. Then, company_id is either a string or a number. Let met guess that it is a string, because the constant is represented with leading zeros. If so, use single quotes:
SELECT c.*
FROM contact c
WHERE company_id = '001' AND
EXISTS (SELECT 1
FROM contactcompany cc
WHERE cc.name ~* 'jack' AND
cc.id = c.contact_company_id
);
Then an index on contact(compnay_id, contact_company_id) makes sense. And for the subquery, contactcompany(id, name).
There may be other alternatives for writing the query, but your question has not provided much information on table sizes, current performance, or the data types.
SELECT
c.ConfigurationID AS RealflowID, c.companyname,
c.companyphone, c.ContactEmail, COUNT(k.caseid)
FROM
dbo.Configuration c
INNER JOIN
dbo.cases k ON k.SiteID = c.ConfigurationId
WHERE
EXISTS (SELECT * FROM dbo.RepairEstimates
WHERE caseid = k.caseid)
AND c.AccountStatus = 'Active'
AND c.domainid = 46
GROUP BY
c.configurationid,c.companyname, c.companyphone, c.ContactEmail
I have this query - I am using the configuration table to get the siteid of the cases in the cases table. And if the case exists in the repair estimates table pull the company details listed and get a count of how many cases are in the repair estimator table for that siteid.
I hope that is clear enough of a description.
But the issue here is the count is not correct with the data that is being pulled. Is there something I could do differently? Different join? Remove the exists add another join? I am not sure I have tried many different things.
Realized I was using the wrong table. The query was correct.
I have a table of LoggedDischarges and another table of ActualDischarges.
I am trying to generate a query that will give me all the fields from ActualDischarges excluding those already in LoggedDischarges based on AgencyID, Program and ActivityEndDate
A client can be in multiple programs and be discharged from multiple on the same day. I need to make sure I get LoggedDischarges from each program.
This is what I have but am not sure how to add the other criteria.
select * from ActualDischarges
where (agencychildid ) not in
(select agencyid from LoggedDischarges)
Thank you,
Steve Hathaway
Even if your DBMS supports multiple columns in a subquery like
where (AgencyID, Program, ActivityEndDate) not in
( select AgencyID, Program, ActivityEndDate
from ... )
you better switch to a NOT EXISTS (in case of any NULLs):
select * from ActualDischarges as aD
where NOT EXISTS
(select * from LoggedDischarges as lD
where aD.AgencyID = lD.AgencyID
and aD.Program = lD. Program
and aD.ActivityEndDate= lD.ActivityEndDate)
For this type of match, I would recommend a LEFT JOIN with an IS NULL at the end to determine that the second table does not have the record:
SELECT a.*
FROM ActualDischarges AS a
LEFT JOIN LoggedDischarges AS l
ON agencyid=agencychildid
AND a.program=l.program
AND a.ActivityEndDate=l.ActivityEndDate
WHERE l.agencyid IS NULL
As a side note, definitely avoid using multiple IN statements for situations like this WHERE NOT IN (...) AND NOT IN (...) etc. as you end up excluding records which match different records in LoggedDischarges for different reasons, which is rarely the desired result.
I have a trip that has many residencies. I need a single query that returns all trips where no residency information has been specified. And all trips that match a specified residency.
I can get the first from this query:
SELECT * FROM `trips` WHERE (((NOT EXISTS (SELECT id FROM residencies WHERE trips.id = residencies.trip_id))
But to get the second, I need to add this bit as well:
INNER JOIN `residencies` ON (`trips`.`id` = `residencies`.`trip_id`)
Adding the join before the WHERE clause is asking for results that have a residency ID and no residency IDs. That obviously returns nothing. So how can I write this to get the full result set in one query? Stored procedures aren't allowed on this.
I'm using Rails, so it's a bonus (but definitely not required) if the answer is Rails-specific. And a huge bonus if someone can show how this can be done with the searchlogic plugin.
Currently, I have the first requirement as a named scope:
Trip.named_scope :residencies_empty, :conditions => ['NOT EXISTS (SELECT id FROM residencies WHERE trips.id = residencies.trip_id)']
The second requirement is available through searchlogic:
Trip.residences_id_equals(id)
The ideal solution would be a searchlogic scope that looks like this:
Trip.residencies_null_or_residencies_id_equals(id)
I suggest using another "EXIST" for the trips with the specific residency:
SELECT * FROM `trips` WHERE
(NOT EXISTS (SELECT id FROM residencies WHERE trips.id = residencies.trip_id))
OR
(EXISTS (SELECT id FROM residencies WHERE trips.id = residencies.trip_id
AND other_criteria_for_specific_residency)
)
This seems to be the most readable solution, but if performance is important, you should check EXPAIN to see how this is optimized (as with most complex queries in MySql).
TRY:
SELECT * FROM `trips`
LEFT JOIN residencies ON trips.id = residencies.trip_id
You will get data in all of the columns from trips, but data will only be populated in columns from residencies where a row existed, if no residencies row existed those columns will be null.
Have you tried using a UNION to combine the results of the two queries?