SQL query JOIN, many-to-many - sql-server

I need small assistance in order to get one query(output) from these tables:
table content
UUID
Type
CatUUID
ZX5N
image
AB6S
ZX5N
image
AB5S
ZX5N
doc
TID5
ZX5N
doc
TID6
table image
UUID
Image
AB6S
test1
AB5S
test2
table doc
UUID
Doc
TID5
test3
TID6
test4
table text
UUID
Body
Desc
ZX5N
text1
text2
the output I want is from text.Body, text.Desc and image.Image
So something like these:
OUTPUT:
UUID
BODY
Desc
Image
Doc
ZX5N
text1
text2
test1,test2
test3,test4
In use is MSSQL 2019
I tried to get only "image" first but failed and couldn't pass that, and have no idea how to then add everything in same row with "comma" seperated as seen from the required output
SELECT text.UUID,text.Body, text.Desc, image.Image
FROM text
LEFT OUTER JOIN content.UUID on text.UUID AND content.Type = 'image'
LEFT OUTER JOIN image on content.CatUUID = image.UUID

You can use STRING_AGG() for this:
SELECT t.UUID, t.Body, t.[Desc],
Image = STRING_AGG(i.[Image], ','),
Doc = STRING_AGG(d.Doc, ',')
FROM dbo.[text] AS t
LEFT OUTER JOIN dbo.content AS c
ON t.UUID = c.UUID
LEFT OUTER JOIN dbo.[image] AS i
ON c.[Type] = 'image' AND c.CatUUID = i.UUID
LEFT OUTER JOIN dbo.doc AS d
ON c.[Type] = 'doc' AND c.CatUUID = d.UUID
GROUP BY t.UUID, t.Body, t.[Desc];
Working example in this fiddle.
Also, try to use [fewer] [reserved] [words], which require delimiting that makes them [harder] [to] [read].

Related

Using a JOIN involving a View and a Table returns more records than expected

Consider these three tables:
Content:
Id(pk), Name, and ContentTypeId(fk from ContentType)
ContentTypeId:
This table will have values like
1 Text
2 Number
...
Id(pk), Value
ContentUpdates:
Id(fk from Content), Status, UpdateDate
To get data from all three for a report there is a View like so:
select C.Id, C.Name, CT.Value, CU.UpdateDate
from ContentUpdates CU
join Content C
On CU.Id = C.Id
join ContentType CT
On C.ContentTypeId = CT.Id;
Currently this particular View gives me 800 records.
I had a similar requirement where in I needed all those columns plus a filter based on the Status column in ContentUpdates table
I thought of using this View joining the 'ContentUpdates' table on the ID.
So I might want to get all the Content that has a Status of 5, for example.
Currently there are only 2 records with that Status, however using a JOIN on the View the result set has way more records than that.
What am I doing wrong?
Can the View be actually used or am I better off with this:
SELECT C.Id, C.Name, CT.Value, CU.UpdateDate
FROM ContentUpdates CU
JOIN Content C
On CS.Id = C.Id
JOIN ContentType CT
On C.ContentTypeId = CT.Id
WHERE CU.Status = 5;
Yes, you can use a view, but you need to expose any of the fields you want to query by or display:
CREATE VIEW content_view
AS
SELECT C.Id, C.Name, CT.Value, CU.UpdateDate, CU.Status
FROM ContentUpdates CU
INNER JOIN Content C On CS.Id = C.Id
INNER JOIN ContentType CT On C.ContentTypeId = CT.Id;
then:
SELECT * FROM content_view WHERE Status = 5;

Left Join Where Clause - How to return a default value when null

Im trying to get a default value when no results are returned. The example im using is im left joining table 1 to table 2 Where the userid = 1. As you can see ted doesnt have a photo in table 2.
Instead of returning nothing in sql server I want it to return No Photo Found.
This is the code im using but it doesnt return the default value.
SELECT
ISNULL(photoName, 'No Photos Found') as photoName
FROM usertable
LEFT OUTER JOIN
phototable
ON
usertable.id= phototable.id
WHERE userID = 1
User Table
Id | User
0 | Jack
Photo Table
ID | Photo
0 | me.jpg
There is a slight typo in your pasted query:
as (photoName
Should be:
as photoName
SELECT
ISNULL(photoName, 'No Photos Found') as photoName,
FROM usertable
LEFT OUTER JOIN
phototable
ON
usertable.id= phototable.id
WHERE userID = 1;
Besides that your code looks ok, so do you have real data instead of your posted data, because it is most likely a data/schema issue.
In your sample data you call the column photo instead of photoname for example.
I would use coalesce():
SELECT coalesce(p.photoName, 'No Photos Found') as photoName
FROM usertable u LEFT OUTER JOIN
phototable p
ON u.id = p.id
WHERE u.userID = 1

SQL Select random from multiple table and order by specific criteria on one table

I need to select a random record from 3 tables and ensure I am ordering by photoOrder
Select TOP 1(a.id), a.mls_number, a.parcel_name, a.property_type, a.ownership_type, b.filename, b.photoOrder, c.county_Name
From property as a
Inner JOIN
listingPhotos as b on a.id = b.ListingID
LEFT JOIN
counties as C on a.county_name = c.id
WHERE a.isCommercial = 'True'
Order By NEWID()
So this query works, but I need to ensure that the b.filename record is ordered by b.photoOrder and thus the b.photoOrder should always be 1.
The b table (listing photos) has multiple photo files per property and I need to only select the photo that is 1st in the photo order.
Thanks
You could subquery your listingPhotos table and limit to WHERE PhotoOrder = 1:
Select TOP 1(a.id), a.mls_number, a.parcel_name, a.property_type, a.ownership_type, b.filename, b.photoOrder, c.county_Name
From property as a
Inner JOIN
(SELECT ListingID , filename, PhotoOrder FROM listingPhotos WHERE PhotoORder = 1
) as b on a.id = b.ListingID
LEFT JOIN
counties as C on a.county_name = c.id
WHERE a.isCommercial = 'True'
Order By NEWID()

database query needed for the following qn

i have 3 database
supplier(sid:integer,sname:string,Address:string)
parts:(pid:integer,pname:string,color:string)
catalog(sid:number,pid:number,cost:string)
qn: find names of suppliers who supply only green parts
Don't know how you are storing your colors (i.e. HTML color defintion, name or what) but a query like this might do the trick:
select supplier.name
from supplier
where supplier.sid in (
-- all the suppliers who supply green parts
select distinct(a.sid)
from catalog a
inner join parts b on a.pid = b.pid
where b.color = 'green')
and supplier.sid not in (
-- all the supplier ids who supply parts that are not green
select distinct(a.sid)
from catalog a
inner join parts b on a.pid = b.pid
where b.color <> 'green')
This returns the supplier names that ONLY stock green parts.
select supplier.sid, supplier.sname, supplier.Address from catalog where part.color = 'green' left join supplier on (catalog.sid = supplier.sid)
left join part on (catalog.pid = parts.pid);

How can I select records in MySQL when a foreign key doesn't return anything?

SELECT videos.id, videos.game_id, videos.xbox360, videos.ps3, videos.pc,
videos.wii, videos.other, videos.thumbnail, videos.vid_info, videos.sdvid,
videos.hdvid, UNIX_TIMESTAMP( videos.date_added ) , game_data.name,
AVG( video_ratings.rating )
FROM videos, game_data, video_ratings
WHERE videos.game_id = game_data.id
AND videos.id = video_ratings.video_id
GROUP BY videos.id, video_ratings.video_id
ORDER BY videos.date_added DESC LIMIT 10;
I am running this query to extract data from three tables video_ratings, game_data, videos...
Now the problem I'm facing is the result only shows the videos that have been rated (or are in table video_ratings) because of AND videos.id = video_ratings.video_id...
Is there any way that I can select the data for all videos and the result shows AVG(video_ratings.rating) as null if ratings for those videos is not present in the video_ratings table (or say none of the videos have been rated so the result must show 10 rows with AVG(video_ratings.rating) column as null ) ...
Thanks
Yeah, just use a left outer inner instead of an inner join (which is what you're doing). I'd also suggest you use the JOIN syntax instead. It's far clearer:
SELECT v.id, v.game_id, v.xbox360, v.ps3, v.pc, v.wii,
v.other, v.thumbnail, v.vid_info, v.sdvid, v.hdvid,
UNIX_TIMESTAMP(v.date_added), gd.name, AVG(vg.rating)
FROM videos v
LEFT JOIN game_data gd ON gd.id = v.game_id
LEFT JOIN video_ratings vr ON v.id = vr.video_id
GROUP BY videos.id, video_ratings.video_id
ORDER BY videos.date_added DESC LIMIT 10

Resources