SQL Server Return 1 Row Per Boat - sql

Basically, what I want to do is join 4 tables together and return 1 row for each boat.
Table Layouts
[Boats]
id, date, section, raft
[Photos]
id, boatid, pthurl, purl
[River_Company]
id, sort, company, company_short
[River_Section]
id, section
Its very simple as far as structure, however, I've having the time of my life trying to get it to return only 1 row. No boat will ever be on the same day, the only thing that's messing this up is the photo table.
If you know a better way for it to return the record table for all the boats boats and only 1 photo from the photo table, please, please post it!!
Desired Format
boats.id, boats.date, river_company.company, river_section.section, photos.purl, photos.pthurl

It's basically how joins work. Since boats and photos are in one-to-many relationships and you want one-to-one-like query, you need to explicitly express it with predicate. For example:
select b.*
from
boats b
inner join photos p
on b.id = p.boatid
where p.id = (select max(id) from photos where boatid = b.id)

Assuming your ID column is the relation that you have designed:
SELECT Boats.* FROM Boats
LEFT OUTER JOIN Photos on Photos.ID =
(
SELECT TOP 1 Photos.ID FROM Photos
INNER JOIN Boats ON Photos.BoatID = Boats.ID
)
INNER JOIN River_Company on River_Company.ID = Boats.ID
INNER JOIN River_Section on River_Section.ID = Boats.ID
So basically, this will:
Guarantee the maximum row count of 1. (It's a bit dirty, but fact is if you have more than one photo, more than one link will be returned otherwise)
If there are no photo's, the boat will still be returned

Related

Count by partition

I have a bunch of rows(fruits) in a table, along with the basic details like fruit name, description color.
I want to know how many people viewed that product, how people liked it, etc...
This is what I tried but it is returning completely wrong numbers:
SELECT
vw.[Id],
vw.[Name],
vw.[Color],
-- This is returning 268 for id 1 but it supposed to be 134
(COUNT(v.PublicImageViewId) OVER (PARTITION BY v.[publicImageId] )) AS [ViewCount],
-- This is returning 268 for id 1 but it supposed to be 2, both these counts are same and wrong
(COUNT(u.PublicImageUpvoteId) OVER (PARTITION BY v.[publicImageId] )) AS [UpvoteCount]
FROM
[PublicImage] vw
LEFT JOIN
[PublicImageUpvote] u ON u.[PublicImageId] = vw.[PublicImageId]
LEFT JOIN
[PublicImageFavourite] f ON f.[PublicImageId] = vw.[PublicImageId]
LEFT JOIN
[PublicImageView] v ON v.PublicImageId = vw.[PublicImageId]
This might not be done like this or I'm doing blunder mistake.
All I wanted is for each product no of views, no of likes, no of favorites ...etc
Tables:
Public Image Table
PublicImageId: PK
name, color
PublicImageUpvote (same for PublicImageView, PublicImageFavourite)
PublicImageUpvoteId: PK
PublicImageId: FK
CreatedBy, Created Date
You must GROUP BY vw.[Id], vw.[Name], vw.[Color] and count the distinct values:
SELECT
vw.[Id],
vw.[Name],
vw.[Color],
COUNT(DISTINCT v.PublicImageViewId) AS [ViewCount],
COUNT(DISTINCT u.PublicImageUpvoteId) AS [UpvoteCount]
FROM [PublicImage] vw
LEFT JOIN [PublicImageUpvote] u ON u.[PublicImageId] = vw.[PublicImageId]
LEFT JOIN [PublicImageFavourite] f ON f.[PublicImageId] = vw.[PublicImageId]
LEFT JOIN [PublicImageView] v ON v.PublicImageId = vw.[PublicImageId]
GROUP BY vw.[Id], vw.[Name], vw.[Color]
May I suggest that you need another table for this
How many people viewed that product, how people liked it, etc...
Then use JOIN

Query showing all records of one table and adding new field

So I have 3 tables which are:
Client = ClientID, ClientName,
Room = RoomID, RoomName
Booking = BookingID, RoomID, ClientID, Status (3 possible values: Booked, Checked-In, Checked-Out), CheckInDate, CheckOutDate
RoomID and ClientID has one-to-many relationship with the fields in booking table
My goal is to create a query that shows all of the rooms in the current time and show their status along with the information of the ocupant (if any) and their check in check out time of each room with these fields:
RoomStatus = RoomName, Status (4 possible values: Empty, Booked, Checked-In, Checked-Out (might be unnecessary since ocupant is no longer in the room)), ClientName, CheckInDate, CheckOutDate
I have managed to create simple query that using the relationships between the tables that shows all of the currently used room that shows all the information I needed. But the problem arise when I'm unable to show the unused room in the query. Since the status fields are in the booking table to keep it simple, the room table has no status field on its own to use.
I've attempted to make an empty query with showing all record of the room using the room id field and make new fields similar with the working ones that has null values and tried to left join and union it with the working one. However, left join only select similar record which only ends up showing the same thing as before and union provides duplicates. But I think this method to be "messy" if it does work.
So I'm open to any other method that is much better than my proposed method. Thank you very much.
I think this is what you are trying to achieve
select *
from #room c
left join
(
select b.*
from #Room r
inner join #Booking b on r.RoomID = b.RoomID
inner join #Client c on c.ClientID = b.ClientID
where CheckInDate = '02/03/2016'
) a on a.RoomID = c.RoomID
In MS Access this can be achived in 2 steps. 1st step will create Query which display result of this query.
select b.*
from #Room r
inner join #Booking b on r.RoomID = b.RoomID
inner join #Client c on c.ClientID = b.ClientID
where CheckInDate = '02/03/2016'
in second step you will do the left join on above QUERY with table rooms. Displaying All records from table room and only those records from above query where join matches.

Select Query from 3 tables with foreign keys

I Have 3 Tables with foreign keys to each other.
I want to write a SQL Server Stored Procedure to select records from one of them.
Now, let's suppose that i want all the Winner records referring to the Player records referring to The Game with the ID=2, how can i proceed?
Thank you.
you have specified all the Winner records So that i have used the left join for player and game. But the Overall code works according to the where condition.
Try This,
select w.* from Winner w
left Join Player p on p.ID_player = w.player_FK
left join Game g on g.ID_game = p.Game_FK
where Game.ID_game = 2
You need to use a SELECT and INNER JOIN then to filter on GameID 2 you can use a WHERE clause.
SELECT ID_Winner, Name, Lastname, Player_FK
FROM Winner
INNER JOIN Player on Player.ID_Pplayer = Winner.Player_FK
INNER JOIN Game ON Game.ID_game = Player.Game_FK
WHERE Game.ID_game = 2

Order by join column but use distinct on another

I'm building a system in which there are the following tables:
Song
Broadcast
Station
Follow
User
A user follows stations, which have songs on them through broadcasts.
I'm building a "feed" of songs for a user based on the stations they follow.
Here's the query:
SELECT DISTINCT ON ("broadcasts"."created_at", "songs"."id") songs.*
FROM "songs"
INNER JOIN "broadcasts" ON "songs"."shared_id" = "broadcasts"."song_id"
INNER JOIN "stations" ON "broadcasts"."station_id" = "stations"."id"
INNER JOIN "follows" ON "stations"."id" = "follows"."station_id"
WHERE "follows"."user_id" = 2
ORDER BY broadcasts.created_at desc
LIMIT 18
Note: shared_id is the same as id.
As you can see I'm getting duplicate results, which I don't want. I found out from a previous question that this was due to selecting distinct on broadcasts.created_at.
My question is: How do I modify this query so it will return only unique songs based on their id but still order by broadcasts.created_at?
Try this solution:
SELECT a.maxcreated, b.*
FROM
(
SELECT bb.song_id, MAX(bb.created_at) AS maxcreated
FROM follows aa
INNER JOIN broadcasts bb ON aa.station_id = bb.station_id
WHERE aa.user_id = 2
GROUP BY bb.song_id
) a
INNER JOIN songs b ON a.song_id = b.id
ORDER BY a.maxcreated DESC
LIMIT 18
The FROM subselect retrieves distinct song_ids that are broadcasted by all stations the user follows; it also gets the latest broadcast date associated with each song. We have to encase this in a subquery because we have to GROUP BY on the columns we're selecting from, and we only want the unique song_id and the maxdate regardless of the station.
We then join that result in the outer query to the songs table to get the song information associated with each unique song_id
You can use Common Table Expressions (CTE) if you want a cleaner query (nested queries make things harder to read)
I would look like this:
WITH a as (
SELECT bb.song_id, MAX(bb.created_at) AS maxcreated
FROM follows aa
INNER JOIN broadcasts bb ON aa.station_id = bb.station_id
INNER JOIN songs cc ON bb.song_id = cc.shared_id
WHERE aa.user_id = 2
GROUP BY bb.song_id
)
SELECT
a.maxcreated,
b.*
FROM a INNER JOIN
songs b ON a.song_id = b.id
ORDER BY
a.maxcreated DESC
LIMIT 18
Using a CTE offers the advantages of improved readability and ease in maintenance of complex queries. The query can be divided into separate, simple, logical building blocks. These simple blocks can then be used to build more complex, interim CTEs until the final result set is generated.
Try by adding GROUP BY Songs.id
I had a very similar query I was doing between listens, tracks and albums and it took me a long while to figure it out (hours).
If you use a GROUP_BY songs.id, you can get it to work by ordering by MAX(broadcasts.created_at) DESC.
Here's what the full SQL looks like:
SELECT songs.* FROM "songs"
INNER JOIN "broadcasts" ON "songs"."shared_id" = "broadcasts"."song_id"
INNER JOIN "stations" ON "broadcasts"."station_id" = "stations"."id"
INNER JOIN "follows" ON "stations"."id" = "follows"."station_id"
WHERE "follows"."user_id" = 2
GROUP BY songs.id
ORDER BY MAX(broadcasts.created_at) desc
LIMIT 18;

SQL Join three tables

I'm learning advanced SQL queries little by little and I'm fairly stumped with a problem:
I have three tables: news, author, and images. Each field in the news table (newsID) is a news story, which then has an associated author in the author table (authorID) and can have any number of images associated in the images table. Each image has and associated (newsID). So each story has one author but can have several images.
I want to make a list of all news stories and use just one of the images as a thumbnail image. The problem is that any sql query I try to list the news items with gives me results equal to the number of images in the images table rather than the number of news items.
I don't know where to go from here. Any help would be greatly appreciated.
If the 3 tables in question are [news], [author] and [image] with appropriate columns, then
Derived Table approach
you can have a derived image table to get one image per news and then join it with the news and author table as shown.
This has been written and tested in SQL Server.
SELECT
N.[newsStoryTitle]
,A.authorName
,I.imageData1
FROM [news] N
LEFT OUTER JOIN author A ON A.newsID = N.newsID
LEFT OUTER JOIN
(
SELECT newsID, MAX(imageData) AS imageData1 FROM [image]
GROUP BY newsID
) AS I ON I.newsID = N.newsID
ORDER BY N.newsID
You could replace the LEFT OUTER JOINs with INNER JOINs if you do not need news without any images.
Correlated Subquery approach (as suggested by Marcelo Cantos)
If the imageData is stored as a text or image, then the MAX in the derived table wouldn't work. In that case, you can use a correlated subquery like this:
SELECT N.newsStoryTitle ,
A.authorName ,
I.imageData
FROM dbo.news N
INNER JOIN dbo.author A ON N.newsID = A.newsID
INNER JOIN dbo.image I ON N.newsID = I.newsID
WHERE imageID = ( SELECT MAX(imageID)
FROM dbo.image
WHERE newsID = N.newsID
)
ORDER BY n.newsID
One option is to add the following predicate:
FROM news JOIN images ...
...
WHERE imageID = (SELECT MAX(imageID)
FROM image
WHERE newsID = news.newsID)
Note that this excludes news items without an image. If you don't want this, you'll need a left join on images and an additional condition on the WHERE:
FROM news LEFT JOIN images ...
...
WHERE imageID IS NULL
OR imageID = (SELECT MAX(imageID)
FROM image
WHERE newsID = news.newsID)
You can to modify the order by on the subselect to get the 1 image per news row you are looking for...
select
....
from news n
left outer join images i on i.imageID = (
select top 1 i2.imageID
from images i2
where i2.newsID = n.newsID
order by --??
)
If you have 3 table in mysql and you want to join it together. for example I have 3 table
1 student
2 subject
3 score
now want to join student with subject and score. so we you this syntax :
select * from student inner join subject inner join score;