select the first row of a joined database - mysql

I need to select the first row of a database joined with another main database.
The main database collects informations about dogs, their race, size, name eccc…
The joined database is linked to the frist and provide dog’s images.
Each dog has different images, more than one.
In the list page of the dogs, I need to show, for each dog, all dog’s details and only the frist image of the joined database, as it was the profile image.
So here u are the structure of the two databases:
//dog_pages database:
id
--
slug
--
name
--
race
--
size
--
description
--
created
--
updated
and:
//dog_images database:
id
--
dog_page_id //this is for the join
--
content
--
img_title
--
img_url
--
img_ftp_path
--
thumb_ftp_path
--
thumb_delete_path
I use this code to generate the query:
SELECT dog_pages.id, dog_pages.slug, dog_pages.name, dog_pages.race, dog_pages.size, dog_pages.description, dog_pages.created, dog_pages.updated, dog_images.id, dog_images.dog_page_id, dog_images.img_url, dog_images.thumb_ftp_path, dog_images.content AS image_content
FROM dog_pages
LEFT JOIN dog_images
ON dog_pages.id = (
SELECT dog_images.dog_page_id
FROM dog_images
WHERE dog_pages.id = dog_images.dog_page_id
LIMIT 1
)
Unfortunately this doesn’t work, the results is to have more than one image for each dog. I needjust one, that in the frist row of the dog_images.

There are multiple methods (including variables). But, taking your method, you can use an aggregation function instead of limit:
SELECT p.id, p.slug, p.name, p.race, p.size, p.description, dog_pages.created, p.updated,
i.id, i.dog_page_id, i.img_url, i.thumb_ftp_path, dog_images.content AS image_content
FROM dog_pages p LEFT JOIN
dog_images i
ON p.id = i.dog_page_id AND
i.id = (SELECT MIN(i2.id)
FROM dog_images i2
WHERE p.id = i2.dog_page_id
);

In the second select you are choosing only Id for joining and you can replace it just with
..=dog_images.dog_page_id
It's exactly what you get from the select
To solve the problem try to use group by dog_pages_I'd
And you should get information only about one image

Related

MySQL multiple joins and count distinct

I need to write query that joins several tables and I need distinct value from one table based on max count().
These are my tables names and columns:
bands:
db|name|
releases_artists:
release_db|band_db
releases_styles
release_db|style
Relations between tables are (needed for JOINs):
releases_artists.band_db = bands.db
releases_styles.release_db = releases_artists.release_db
And now the query that I need to write:
SELECT b.name, most_common_style
LEFT JOIN releases_artists ra ON ra.band_db = b.db
and here I need to find the most common style from all band releases
JOIN(
SELECT DISTINCT style WHERE releases_styles.release_db = ra.release_db ORDER BY COUNT() DESC LIMIT 1
)
FROM bands b
WHERE b.name LIKE 'something'
This is just a non working example of what I want to accomplish. It would be great if someone could help me build this query.
Thanks in advance.
EDIT 1
Each artist from table bands can have multiple records from releases_artists table based on band_db and each release can have multiple styles from releases_styles based on release_db
So if I search for b.name LIKE '%ray%' it returns something similar to:
`bands`:
o7te|Ray Wilson
9i84|Ray Parkey Jr.
`releases_artists` for Ray Wilson:
tv5c|o7te (for example album `Change`)
78wz|o7te (`The Next Best Thing`)
nz7c|o7te (`Propaganda Man`)
`releases_styles`
tv5c|Pop
tv5c|Rock
tv5c|Alternative Pop/Rock
----
78wz|Rock
78wz|Pop
78wz|Classic Rock
I need style name that repeats mostly from all artist releases as this artist main style.
Ok, this is a bit of a hack. But the only alternatives I could think of involve heaps of nested subqueries. So here goes:
SELECT name
, SUBSTRING_INDEX(GROUP_CONCAT(style ORDER BY release_count DESC SEPARATOR '|'), '|', 1) AS most_common_style
FROM (
SELECT b.db
, b.name
, rs.style
, COUNT(*) AS release_count
FROM bands b
JOIN releases_artists ra ON ra.band_db = b.db
JOIN releases_styles rs ON rs.release_db = ra.release_db
GROUP BY b.db, rs.style
) s
GROUP BY db;

MySQL View Creation

I have two tables:
parking_lot
id
name
parking_spot
id
parking_lot_id
available
I would like to create a view that looks like this:
parking_lot_view
id
name
num_spots_available
What would the query to create this view be for a MySQL DB?
If you need to create a view, first start by creating a Select SQL Statement joining whatever tables you need. Then you just add "CREATE VIEW AS" at the beginning and Execute.
In your specific case, this should do the trick (I assumed 'available' is an Integer that contains 0 for unavailable and 1 for available, since you do not specify that in your question):
CREATE VIEW parking_lot_view AS
select L.id, L.name, count(*) available_spots
from parking_lot L inner join parking_spot S on S.parking_lot_id = L.id
where S.available <> 0
group by L.id, L.name
This is a simple query, so I assume you are pretty new to MySQL and databases. You should definitely try to understand how this works and study up on the subject:
create view parking_lot_view as
select pl.id, pl.name, sum(available) as NumAvailable
from parking_spot ps join
parking_lot pl
on ps.parking_lot_id = pl.id
group by pl.id, pl.name;
This assumes that available is 1 when available and 0 otherwise.

Select Record Conditional Random #MySQL

I have two tables, one for still images and one with this property, both are linked so that a property can have no pictures. Would you like to "select" where I can select all properties and just a random picture of this property. How to do this?
Exemplifying best, I pick a random image from the image table for each record in the table that has motionless pictures. Want to select this randomly. What I could do was to select all images for each record of the bank property. I just want each record imovel a respective random image.
The sql is below:
select distinct
imovel.nome as 'NOME',
imovel.valor as 'VALOR',
imovel.quarto as 'QUARTO',
imovel.suite as 'SUITE',
cidade.nome as 'CIDADE',
bairro.nome as 'BAIRRO',
(select distinct nome from tabimagem img where img.cdimovel = imagem.cdimovel order by rand() limit 1) as 'IMAGEM'
from tabimovel imovel
inner join tabcidade cidade on imovel.cdcidade = cidade.codigo
inner join tabbairro bairro on imovel.cdBairro = bairro.codigo
inner join tabimagem imagem on imagem.cdImovel = imovel.codigo
order by rand()
In SQL server add TOP 1 after SELECT, and order as ORDER BY NEWID().
In MySQL, order should be ORDER BY RAND(), followed by LIMIT 1.
That should work.

Correlated Subquery in a MySQL CASE Statement

Here is a brief explanation of what I'm trying to accomplish; my query follows below.
There are 4 tables and 1 view which are relevant for this particular query (sorry the names look messy, but they follow a strict convention that would make sense if you saw the full list):
Performances may have many Performers, and those associations are stored in PPerformer. Fans can have favorites, which are stored in Favorite_Performer. The _UpcomingPerformances view contains all the information needed to display a user-friendly list of upcoming performances.
My goal is to select all the data from _UpcomingPerformances, then include one additional column that specifies whether the given Performance has a Performer which the Fan added as their favorite. This involves selecting the list of Performers associated with the Performance, and also the list of Performers who are in Favorite_Performer for that Fan, and intersecting the two arrays to determine if anything is in common.
When I execute the below query, I get the error #1054 - Unknown column 'up.pID' in 'where clause'. I suspect it's somehow related to a misuse of Correlated Subqueries but as far as I can tell what I'm doing should work. It works when I replace up.pID (in the WHERE clause of t2) with a hard-coded number, and yes, pID is an existing column of _UpcomingPerformances.
Thanks for any help you can provide.
SELECT
up.*,
CASE
WHEN EXISTS (
SELECT * FROM (
SELECT RID FROM Favorite_Performer
WHERE FanID = 107
) t1
INNER JOIN
(
SELECT r.ID as RID
FROM PPerformer pr
JOIN Performer r ON r.ID = pr.Performer_ID
WHERE pr.Performance_ID = up.pID
) t2
ON t1.RID = t2.RID
)
THEN "yes"
ELSE "no"
END as pText
FROM
_UpcomingPerformances up
The problem is scope related. The nested Selects make the up table invisible inside the internal select. Try this:
SELECT
up.*,
CASE
WHEN EXISTS (
SELECT *
FROM Favorite_Performer fp
JOIN Performer r ON fp.RID = r.ID
JOIN PPerformer pr ON r.ID = pr.Performer_ID
WHERE fp.FanID = 107
AND pr.Performance_ID = up.pID
)
THEN 'yes'
ELSE 'no'
END as pText
FROM
_UpcomingPerformances up

Sql Result IN a Query

dont blame for the database design.I am not its database architect. I am the one who has to use it in current situation
I hope this will be understandable.
I have 3 tables containing following data with no foreign key relationship b/w them:
groups
groupId groupName
1 Admin
2 Editor
3 Subscriber
preveleges
groupId roles
1 1,2
2 2,3
3 1
roles
roleId roleTitle
1 add
2 edit
Query:
SELECT roles
from groups
LEFT JOIN preveleges ON (groups.groupId=preveleges.groupId)
returns specific result i.e roles.
Problem: I wanted to show roleTitle instead of roles in the above query.
I am confused how to relate table roles with this query and returns required result
I know it is feasible with coding but i want in SQL.Any suggestion will be appreciated.
SELECT g.groupName,
GROUP_CONCAT(r.roleTitle
ORDER BY FIND_IN_SET(r.roleId, p.roles))
AS RoleTitles
FROM groups AS g
LEFT JOIN preveleges AS p
ON g.groupId = p.groupId
LEFT JOIN roles AS r
ON FIND_IN_SET(r.roleId, p.roles)
GROUP BY g.groupName ;
Tested at: SQL-FIDDLE
I would change the data structure it self. Since It's not normalised, there are multiple elements in a single column.
But it is possible with SQL, if for some (valid) reason you can't change the DB.
A simple "static" solution:
SELECT REPLACE(REPLACE(roles, '1', 'add'), '2', 'edit') from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)
A more complex but still ugly solution:
CREATE FUNCTION ReplaceRoleIDWithName (#StringIds VARCHAR(50))
RETURNS VARCHAR(50)
AS
BEGIN
DECLARE #RoleNames VARCHAR(50)
SET #RoleNames = #StringIds
SELECT #RoleNames = REPLACE(#RoleNames, CAST(RoleId AS VARCHAR(50)), roleTitle)
FROM roles
RETURN #RoleNames
END
And then use the function in the query
SELECT ReplaceRoleIDWithName(roles) from groups
LEFT JOIN preveleges ON(groups.groupId=preveleges.groupId)
It is possible without function, but this is more readable. Made without editor so it's not tested in anyway.
You also tagged the question with PostgreSQL and it's actually quite easy with Postgres to work around this broken design:
SELECT grp.groupname, r.roletitle
FROM groups grp
join (
select groupid, cast(regexp_split_to_table(roles, ',') as integer) as role_id
from privileges
) as privs on privs.groupid = grp.groupid
join roles r on r.roleid = privs.role_id;
SQLFiddle: http://sqlfiddle.com/#!12/5e87b/1
(Note that I changed the incorrectly spelled name preveleges to the correct spelling privileges)
But you should really, really re-design your data model!
Fixing your design also enables you to define foreign key constraints and validate the input. In your current model, the application would probably break (just as my query would), if someone inserted the value 'one,two,three' into the roles table.
Edit
To complete the picture, using Postgres's array handling the above could be slightly simplified using a similar approach as MySQL's find_in_set()
select grp.groupname, r.roletitle
from groups grp
join privileges privs on grp.groupid = privs.groupid
join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
In both cases if all role titles should be shown as a comma separated list, the string_agg() function could be used (which is equivalent to MySQL's group_concat()
select grp.groupname, string_agg(r.roletitle, ',')
from groups grp
join privileges privs on grp.groupid = privs.groupid
join roles r on r.roleid::text = any (string_to_array(privs.roles, ','))
group by grp.groupname