Write an SQL query search - sql

I need to write a sql query that will find users that have at least 2 different books from set of (book1, book2 and book3) . what technique can be used to write such a query?
I want to find all users who own at least 2 books from a specified set of books ('book_1','book_2','book_3') but do not own any of the books in a second specified set ('book_4')?
EDIT:
OP couldn't explain what he is actually looking for. What OP actually trying to do is:
Find all users who own at least 2 different books and exclude those users who has a book called 'book_4'.

Try this:
SELECT Users,Count(DISTINCT Books) as CountOfBooks
FROM TableName
GROUP BY Users
HAVING COUNT(DISTINCT Books) >= 2
Explanation:
Here, we are grouping the table contents with users field and counting the number of distinct books that each user has. The HAVING clause is helpful to filter the result with the count of distinct book.
You can change the number 2 with the count you need. And = can be used for exact match instead of atleast.
See an example in SQL Fiddle.
EDIT:
For excluding users with book_4, try this:
SELECT Users,Count(DISTINCT Books) as CountOfBooks
FROM TableName
WHERE Users NOT IN (SELECT Users FROM TableName WHERE Books = 'book_4')
GROUP BY Users
HAVING COUNT(DISTINCT Books) >= 2
OR a faster version (without using IN):
SELECT T1.Users,Count(DISTINCT T1.Books) as CountOfBooks
FROM TableName T1 LEFT JOIN
(SELECT Users
FROM TableName
WHERE Books = 'Book4') T2 ON T2.Users=T1.Users
WHERE T2.Users IS NULL
GROUP BY T1.Users
HAVING COUNT(DISTINCT T1.Books)>=2
An example in SQL Fiddle.

Try this,
select USERS,count(distinct BOOKS) from myTable
where BOOKS in('Book1','Book2','Book3')
group by USERS
having count(distinct BOOKS) >=2

Related

Query build to find records where all of a series of records have a value

Let me explain a little bit about what I am trying to do because I dont even know the vocab to use to ask. I have an Access 2016 database that records staff QA data. When a staff member misses a QA we assign a job aid that explains the process and they can optionally send back a worksheet showing they learned about what was missed. If they do all of these ina 3 month period they get a credit on their QA score. So I have a series of records all of whom have a date we assigned the work(RA1) and MAY have a work returned date(RC1).
In the below image "lavalleer" has earned the credit because both of her sheets got returned. "maduncn" Did not earn the credit because he didn't do one.
I want to create a query that returns to me only the people that are like "lavalleer". I tried hitting google and searched here and access.programmers.co.uk but I'm only coming up with instructions to use Not null statements. That wouldn't work for me because if I did a IS Not Null on "maduncn" I would get the 4 records but it would exclude the null.
What I need to do is build a query where I can see staff that have dates in ALL of their RC1 fields. If any of their RC1 fields are blank I dont want them to return.
Consider:
SELECT * FROM tablename WHERE NOT UserLogin IN (SELECT UserLogin FROM tablename WHERE RCI IS NULL);
You could use a not exists clause with a correlated subquery, e.g.
select t.* from YourTable t where not exists
(select 1 from YourTable u where t.userlogin = u.userlogin and u.rc1 is null)
Here, select 1 is used purely for optimisation - we don't care what the query returns, just that it has records (or doesn't have records).
Or, you could use a left join to exclude those users for which there is a null rc1 record, e.g.:
select t.* from YourTable t left join
(select u.userlogin from YourTable u where u.rc1 is null) v on t.userlogin = v.userlogin
where v.userlogin is null
In all of the above, change all occurrences of YourTable to the name of your table.

Querying records that meet muliple criteria

Hi I’m trying to write a query and I’m struggling to figure out how to go about it.
I have a suppliers table and a supplier parts table I want to write a query that lists suppliers that have specified related Parts in the supplier parts table. If a supplier doesn’t have all specified related parts then they should not be listed.
At the moment I have written a very basic query that lists the supplier if they have a related supplier part that meets the criteria.
SELECT id ,name
FROM
efacdb.dbo.suppliers INNER JOIN [efacdb].[dbo].[spmatrix] ON
id = spmsupp
WHERE spmpart
IN ('ALUM_5083', 'ALUM_6082')
I only want to show the supplier if they have both parts related. Does anyone know how I could do this?
Use a subquery with counting distinct occurences:
select * from suppliers s
where 2 = (select count(distinct spmpart) from spmatrix
where id = spmsupp and spmpart in ('ALUM_5083', 'ALUM_6082'))
As a note, you can modify your query to get what you want, just by using an aggregation:
SELECT id, name
FROM efacdb.dbo.suppliers INNER JOIN
[efacdb].[dbo].[spmatrix]
ON id = spmsupp
WHERE spmpart IN ('ALUM_5083', 'ALUM_6082')
GROUP BY id, name
HAVING MIN(spmpart) <> MAX(spmpart);
If you know there are no duplicates, then having count(*) = 2 also solves the problem.

Select all in table where a column in table 1 exists in another table and a second column equals a variable in second table

I know the title is confusing but its the best I could explain it. Basically im developing a cinema listings website for a company which owns two cinemas. So I have a database which has the two tables "Films" and "Listings" with data for both cinemas in them.
I'm trying to select all films and their data for one cinema if the films name shows up in the listings (since the two cinemas share all films but in the table but the may not have the same films showing)
Here is what i have come up with but I run into a problem as when the "SELECT DISTINCT" returns more than one result it obviously cant be matched with the FilmName on tbl Films.
How can i check this value for all FilmNames on tblFilms?
SELECT *
FROM tblFilms
WHERE FilmName = (SELECT DISTINCT FilmName FROM tblListings WHERE Cimema = 1)
use IN if the subquery return multiple values,
SELECT *
FROM tblFILMS
WHERE FilmName IN (SELECT DISTINCT FilmName FROM tblListings WHERE Cimema = 1)
Another way to solve thius is by using JOIN (which I recommend)
SELECT DISTINCT a.*
FROM tblFILMS a
INNER JOIN tblListings b
ON a.FilmName = b.FilmName AND
b.Cimema = 1
for faster query execution, add an INDEX on FilmName on both tables.
If you have your schemas for the tables, that would help.
That said, I believe what you want to look at is the JOIN keyword. (inner/outer/left/etc). That's exactly what JOIN is meant to do (ie your title).

Retrieving alternate attribute values in GROUP BY query?

Let me explain what I mean with that question:
Lets say I have to tables like these:
customers
id customer location
1 Adam UK
2 Pete US
values
id value
1 10
1 7
2 3
2 41
Let's ignore here for a moment that that (and the following query) wouldn't make a lot of sense. It's meant as a simplified example.
Now, if I run this query
SELECT id, customer, value FROM customers INNER JOIN values GROUP BY id
I should get this result (distinct by id)
id customer value
1 Adam 10
2 Pete 3
What I would like to be able to do is get that to use it in a search result list, but for actual displaying of the results I'd like to do something like this:
Customer: Adam
Values: 10, 7
So, basically, while I need to have a result set that's distinct for the ID, I'd still like to somehow save the rows dropped by the GROUP BY to show the values list like above. What is the best way to do this?
Look at http://mysql.com/group_concat - which only will work in MySql.
Better link: http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html#function_group-concat
Technically, the following is not valid SQL even though MySQL allows it:
Select customers.id, customers.customer, values.value
From customers
Inner Join values
On values.id = customers.id
Group By customers.id
The SQL spec requires that every column in the Select clause be referenced in the Group By or in an aggregate function. However, given what you said later in your post, what I think you want is GROUP_CONCAT as first mentioned by Erik (+1) which is a function specific to MySQL:
Select customers.customer, Group_Concat(values.value)
From customers
Inner Join values
On values.id = customers.id
Group By customers.customer

Fetch last item in a category that fits specific criteria

Let's assume I have a database with two tables: categories and articles. Every article belongs to a category.
Now, let's assume I want to fetch the latest article of each category that fits a specific criteria (read: the article does). If it weren't for that extra criteria, I could just add a column called last_article_id or something similar to the categories table - even though that wouldn't be properly normalized.
How can I do this though? I assume there's something using GROUP BY and HAVING?
Try with:
SELECT *
FROM categories AS c
LEFT JOIN (SELECT * FROM articles ORDER BY id DESC) AS a
ON c.id = a.id_category
AND /criterias about joining/
WHERE /more criterias/
GROUP BY c.id
If you provide us with the Tables schemas, we could be a little more specific, but you could try something like (12.2.9.6. EXISTS and NOT EXISTS, SELECT Syntax for LIMIT)
SELECT *
FROM articles a
WHERE EXISTS (
SELECT 1
FROM articles
where category_id = a.category_id
AND <YourCriteria Here>
ORDER BY <Order Required : ID DESC, LastDate DESC or something?
LIMIT 1
)
Assuming the id's in the articles table represent always increasing numbers, this should work. Using the id is not semantically correct IMHO, you should actually use a time/date tamp field if one is available.
SELECT * FROM articles WHERE article_id IN
(
SELECT
MAX(article_id)
FROM
articles
WHERE [your filters here]
GROUP BY
category_id
)