I am stuck and I am trying to find a solution, so please help!
I have 3 tables:
Books (id, title, ...)
Authors (id, name, surname, ...)
book_authors (bookID, authorID, whatisdoing)
Now I want to retrieve all books depending on the title (user search) and all the other info (author name, surname). But, I want the book titles to be unique with only the first occurrence of the book_authors.whatisdoing to be shown.
In MS Access I achieved that with first function, but now first does not work and with min I didn't get the results I want.
Any help would be appreciate.
The query in Access was:
SELECT
First(book_authos.whatisdoing) AS FirstOfidiothta_ID,
First(authors.name) AS onoma,
First(authors.surname) AS eponymo,
books.ID, books.title, books.photoLink
FROM (books
INNER JOIN book_authors ON books.ID = book_authors.book_ID)
INNER JOIN authors ON book_authors.author_ID = authors.ID
GROUP BY
books.ID, books.titlos, books.photoLink, books.active
HAVING
(((books.titlos) Like '%" & textString & "%') AND
((books.active)=True) AND ((First(authors.active))=True))
ORDER BY
First(book_authos.whatisdoing), books.title
EDIT: Changed based on OP comments.
EDIT 2: Revised to correct flaws.
You might give this a try.
SELECT aba.name, aba.surname, aba.whatisdoing,
b.ID, b.title, b.photoLink
FROM Books b
JOIN
(
SELECT ba.bookID, ba.whatisdoing, a.name, a.surname,
ROW_NUMBER() OVER (PARTITION BY ba.bookID ORDER BY ba.whatisdoing) AS sequence
FROM book_authors ba
JOIN Authors a ON ba.authorID = a.id
WHERE a.active = 1
) AS aba ON b.id = aba.bookID
WHERE b.title LIKE '%' + #textString + '%'
AND b.active = 1
AND aba.sequence = 1
The ROW_NUMBER function assigns a row number to the row based on the groups defined in the PARTITION BY clause and the order defined by the ORDER BY clause.
#textString is a SQL Server variable. I'm not sure how you would assign this in your situation.
The boolean data type is BIT in SQL Server and the values are 0 for false and 1 from true.
Related
I am doing a course on Relational Databases, MySQL to be more especific. We need to create some SELECT queries for a project. The project is related to music. It has tables to represent musicians (musician), bands (band) and the musician ability to do a certain task, like singing or playing the guitar (act).
Table musician contains :
id
name
stagename
startyear
Table band contains :
code
name
type ("band" or "solo")
startyear
And finally, table act contains :
band (foreign key to code of "band" table)
musician (foreign key to id of "musician" table)
hability (guitarist, singer, like that... and a foreign key to another table)
earnings
I have doubts in two exercises, the first one asks to select musicians id and stagename who participate with more acts in bands whose type is solo.
My solution for the first one is this:
SELECT ma.id, ma.stagename
FROM musician ma, act d, band ba
WHERE ma.id = d.musician
AND ba.code = d.band
AND ba.type = "solo"
GROUP BY ma.id, ma.stagename
HAVING COUNT(ma.id) = (SELECT COUNT(d2.musician) AS count
FROM act d2, band ba2
WHERE d2.band = ba2.code
AND ba2.type = "solo"
GROUP BY d2.musician
ORDER BY count DESC
LIMIT 1);
The second one is very similar to the last one. We need to select, for every startyear, the id and stagename of a musician who can do more acts, with the corresponding number of acts and the maximum and minimum of his cachet. This is my solution:
SELECT ma.startyear, ma.id, ma.stagename, COUNT(ma.id) AS NumActs, MIN(d.earnings), MAX(d.earnings)
FROM musician ma, act d, band ba
WHERE ma.id = d.musician
AND ba.code = d.band
AND ba.type = "solo"
GROUP BY ma.year, ma.id, ma.stagename
HAVING COUNT(ma.id) = (SELECT COUNT(d2.musician) AS count
FROM act d2, band ba2
WHERE d2.band = ba2.code
AND ba2.type = "solo"
GROUP BY d2.musician
ORDER BY count DESC
LIMIT 1);
The results with my dummy data are perfect but my teacher told us we should avoid using the LIMIT option, but that's the only way we can get the highest number, at least with what we know right now.
I've seen a lot of subqueries after the FROM statement to solve this problem, however, for this project we can't use subqueries inside FROM. Is this really possible without LIMIT ?
Thanks in advance.
It is possible, but much worse than with sub-query in from or limit. So I'd never use it in real life :)
Well, long story short, you can do something like this:
SELECT
m.id
, m.stagename
FROM
musician m
INNER JOIN act a ON (
a.musician = m.id
)
INNER JOIN band b ON (
b.code = a.band
AND b.type = 'solo'
)
GROUP BY
m.id
, m.stagename
HAVING
NOT EXISTS (
SELECT
*
FROM
act a2
INNER JOIN band b2 ON (
b2.code = a2.band
AND b2.type = 'solo'
)
WHERE
a2.musician != a.musician
GROUP BY
a2.musician
HAVING
COUNT(a2.musician) > COUNT(a.musician)
)
;
I think you can understand the idea from the query itself as it's pretty straightforward. However, let me know if you need an explanation.
It is possible that your restriction was slightly different and you were not allowing to use subquery in your main FROM part only.
P.S. I'm also use INNER JOIN ... ON syntax as it is easier to see what are table join conditions and what are where conditions.
P.P.S. It might be mistakes in query as I do not have your data structure so cannot execute the query and check. I only checked if the idea works with my test table.
EDIT I just re-read the question; my initial reading missed that inline views are disallowed.
We can avoid the ORDER BY ... DESC LIMIT 1 construct by making the subquery into an inline view (or, a "derived table" in the MySQL parlance), and using a MAX() aggregate.
As a trivial demonstration, this query:
SELECT b.foo
FROM bar b
ORDER
BY b.foo DESC
LIMIT 1
can be emulated with this query:
SELECT MAX(c.foo) AS foo
FROM (
SELECT b.foo
FROM bar b
) c
An example re-write of the first query in the question
SELECT ma.id
, ma.stagename
FROM musician ma
JOIN act d
ON d.musician = ma.id
JOIN band ba
ON ba.code = d.band
WHERE ba.type = 'solo'
GROUP
BY ma.id
, ma.stagename
HAVING COUNT(ma.id)
= ( SELECT MAX(c.count)
FROM (
SELECT COUNT(d2.musician) AS count
FROM act d2
JOIN band ba2
ON ba2.code = d2.band
WHERE ba2.type = 'solo'
GROUP
BY d2.musician
) c
)
NOTE: this is a demonstration of a rewrite of the query in the question; this makes no guarantee that this query (or the query in the question) are guaranteed to return a result that satisfies any particular specification. And the specification given in the question is not at all clear.
from the following table,
how will below output should be queried?
My initial query is:
select
bpai.sequence_id, bpai.last_name, bpai.given_name,
bpai.middle_name, bpai.middle_initial,
bpai.gender, bpai.birth_date, bpai.birth_place_via_psgc, bpai.citizenship,
bpai.primary_mobile_number, bpai.primary_email_address, count(*)
from bpaitbl bpai
inner join (select
*, count(*) as countof
from bpaitbl
group by
last_name, middle_name,
gender, birth_date, citizenship
having (count(*) > 1)
) profil on bpai.last_name like profil.middle_name
and bpai.gender = profil.gender
and bpai.birth_date = profil.birth_date
and bpai.citizenship = profil.citizenship
;
and can't make the output anyhow i tried. please help.
Since you don't say in your question, but mention in your title, what the result set represents, I presume you want a list of rows with duplicate records.
The following query will list all of the records with duplicate records, showing the record with the highest sequence_id of the duplicates:
SELECT
a.sequence_id,
a.last_name,
a.given_name,
a.middle_name,
a.gender,
a.birth_date,
a.citizenship
FROM bpaitbl a
LEFT JOIN bpaitbl b
ON a.last_name = b.last_name AND
a.given_name = b.given_name AND
a.middle_name = b.middle_name AND
a.gender = b.gender AND
a.birth_date = b.birth_date AND
a.citizenship = b.citizenship AND
a.sequence_id > MAX(b.sequence_id)
WHERE b.sequence_id IS NULL;
GROUP BY
a.last_name,
a.given_name,
a.middle_name,
a.gender,
a.birth_date,
a.citizenship
To show the record with the lowest sequence_id, change the > to <. If you want all rows, including those without duplicates, remove the where clause.
slightly complex problem here I'd like to solve in SQL:
I have duplicate person records like these:
Many examples like this where the name was misspelled, so my inbound ETL code didn't detect them as duplicates.
I have a dedupping workflow, that culls suspected duplicates with same first/last names and let's the user collapse them. The query for this page is below:
SELECT * FROM
((address
INNER JOIN ((person AS a
INNER JOIN (SELECT
idperson, last_name, first_name, middle, suffix
FROM
person
GROUP BY last_name , first_name
HAVING Count(*) > 1) AS b ON (a.first_name = b.first_name)
AND (a.last_name = b.last_name))
INNER JOIN constituent ON a.constituent_idconstituent = constituent.idconstituent
INNER JOIN constituent_address ON a.constituent_idconstituent = constituent_address.constituent_idconstituent) ON address.idaddress = constituent_address.address_idaddress)
INNER JOIN city ON address.city_idcity = city.idcity)
INNER JOIN
state ON city.state_idstates = state.idstates
WHERE
a.last_name = 'Cascarano'
ORDER BY a.last_name , a.first_name , a.middle , address.line_1 ASC
However, my example above where the first names are spelled differently, isn't caught by this query.
Is there a substring or some other SQL trick I can apply here, to somehow maybe chop up the first_name field and look for, maybe 75% letter match? I know I'm reaching...
Thanks!!!!!
SELECT area_id,
area_name,
(select count(*) from applications
where claims_status=1 and
center_name=c.area_id) as cont
FROM apparea c where cont<>0
I am trying to get fields and relevant count from anothere table, but the above query is not working. The query is involved two different tables(apparea, applications). The above query has error and I am looking for the alternate way to achieve this.
The alias for your column cont is not available in the WHERE clause. You will want to use something similar to this:
SELECT area_id,
area_name,
cont
FROM
(
SELECT area_id,
area_name,
(select count(*)
from applications
where claims_status=1
and center_name=c.area_id) as cont
FROM apparea c
) c
where cont<>0
This can also be written using a LEFT JOIN:
select c.area_id,
c.area_name,
a.cont
from apparea c
left join
(
select count(*) cont,
center_name
from applications
where claims_status=1
group by center_name
) a
on c.area_id = a.center_name
Try this query
SELECT
c.area_id,
c.area_name,
cnt
FROM
apparea c,
(select
center_name,
count(*) AS cnt
from
applications
where
claims_status=1
GROUP BY
center_name
HAVING
count(*) > 0) cont
where
c.area_id = cont.center_name;
Got the count for each center_name and then joined table to get count for each area
Use HAVING rather than where.
As it is problem with aliases.
It is not permissible to refer to a column alias in a WHERE clause, because the column
value might not yet be determined when the WHERE clause is executed.
See Section C.5.5.4, “Problems with Column Aliases”.
http://dev.mysql.com/doc/refman/5.0/en/problems-with-alias.html
From: http://dev.mysql.com/doc/refman/5.0/en/select.html
I have an SQL LIKE:
SELECT S.*,
(SELECT I.NAME FROM institution I, inst_map IM
WHERE IM.STUDENT = S.ID AND IM.INSTITUTION = I.ID) as INSTITUTIONS
FROM student S
In this case it is possible for my subquery to return multiple records (I will get an error: Subquery returns more than 1 row).
How to show those multiple values from my subquery in one field (in my case INSTITUTIONS ) separated by commas?
All ideas are welcome.
Try this query -
SELECT s.*, GROUP_CONCAT(t.NAME) INSTITUTIONS FROM student s
LEFT JOIN (SELECT * FROM institution i
JOIN inst_map im
ON im.INSTITUTION = i.ID
) t
ON s.ID = t.STUDENT
GROUP BY s.ID
The GROUP_CONCAT function will help you to get values separated by commas.
DECLARE #List VARCHAR(5000)
SELECT #List = COALESCE(#List + ', ' + Display, Display)
FROM TestTable
Order By Display
query is taken from following link, and the article explain the query perfectly, I hope it works
http://www.mitchelsellers.com/blogs/articletype/articleview/articleid/289/creating-comma-separated-list-in-sql.aspx
P.S Its for SQL Server, i guess