SQL Views on multiple tables - sql-server

I have a database of a Travel Agency which contains tables Hotel, Motel and RentalHome, all of which refer to the Accommodation table using a foreign key that references the
accommodation_id of that table.
I wish to create a View so that I can identify what a particular accommodation ID refers to; Hotel, Motel, or RentalHome.
CREATE VIEW IdentifyAccom AS
SELECT Accommodation.accom_id AS AccomID, Hotel.hotel_name AS Hotel_Name
FROM Accommodation, Hotel
WHERE Accommodation.accom_id = Hotel.accom_id
How can I go about this? I tried the following approach but to no avail.
CREATE VIEW IdentifyAccom AS
SELECT Accommodation.accom_id AS AccomID, Hotel.hotel_name AS Hotel_Name, Motel.motel_name
FROM Accommodation, Hotel, Motel
WHERE Accommodation.accom_id = Hotel.accom_id,
WHERE Accommodation.accom_id = Motel.accom_id

Presumably all accomodations are either a Hotel or a Motel? If so you can use something like IIF to determine the type and ISNULL or COALESCE to populate a name.
CREATE VIEW IdentifyAccom
AS
SELECT a.accom_id AS AccomID, IIF(h.accom_id IS NOT NULL, 'HOTEL', 'MOTEL') AS Accom_Type,
ISNULL(h.hotel_name, m.motel_name) AS Accom_Name
FROM Accommodation a
LEFT JOIN Hotel h ON h.accom_id = a.accom_id
LEFT JOIN Motel m ON m.accom_id = a.accom_id

Try with inner join
CREATE VIEW IdentifyAccom AS
SELECT
A.accom_id AS AccomID
,H.hotel_name AS Accom
FROM Accommodation A
INNER JOIN Hotel H ON H.accom_id = A.accom_id
UNION
SELECT
A.accom_id AS AccomID
,M.motel_name AS Accom
FROM Accommodation A
INNER JOIN Motel M ON M.accom_id = A.accom_id

Related

Sql Recursive Function only show nods that have specifik relation

I have a Link structure table with ID and parentID.
ID, Parent, name
1,1
2,1
3,2
4,3
5,3
To this table I have a structure_article relation table
in this table I have relation between a Link and a article.
struture_article
structid, articleID
4,1000
4,1001
5,1002
Every article in that table have a supplier.
Now i am trying to create a recursive function that creates the tree
nods if i pick a specific supplier.
Article table
ArticleID, SUPPLIER ID
1000,1
1001,2
1002,2
If I pick articles with supplier 1 then I want the function to show me the tree structure that have articles from that supplier.
I have 20 suppliers and 300 links in the DB now i want only to show articles from the suppliers i pick. I don want any empty nods.
Is this even possible do create with a recursive function in Sql Server version 2008?
I tyied wiht this code the problem is that i get only nods that have articles connected
WITH a
AS (SELECT *
FROM structure
WHERE parent = 125
UNION ALL
SELECT m.*
FROM structure m
JOIN a
ON m.parent = a.internidstructure)
SELECT *
FROM a
WHERE internidstructure IN (SELECT DISTINCT( internidstructure )
FROM dbo.articles
INNER JOIN dbo.structure_article
ON dbo.articles.internidarticle =
dbo.structure_article.internidarticle
WHERE ( dbo.articles.internidsupplier IN (SELECT
internidsupplier
FROM site_sup
WHERE
internidsite = 1) ))
ORDER BY parent,
sortno
Try using a left join instead of an inner join.
I'm not sure to have understood your need but if you want to have a new tree table without nodes not linked to a supplier, this query can work.
WITH A AS
(
SELECT S.ID as ID, S.Parent as Parent, 1 as art_linked
FROM structure S
INNER JOIN dbo.structure_article SA
ON S.ID = SA.structid
INNER JOIN Article AR
ON AR.ArticleID = SA.ArticleID
WHERE AR.SupplierID = 1
UNION ALL
SELECT S.ID, S.Parent, 0
FROM structure S
INNER JOIN A
ON A.parent = S.ID
WHERE S.ID <> S.Parent
)
SELECT A.ID, A.Parent, MAX(A.art_linked)
FROM A
GROUP BY A.ID, A.Parent

How to join additional table when left outer not working

I have an existing proc which I have chopped up for brevity's sake
SELECT col1, col2
FROM (
col1, col2
SELECT col3--aggregate columns
FROM iep i
INNER JOIN student s ON s.studentID = i.studentID
INNER JOIN dbo.IDuration id ON i.IepID = id.iepID
INNER JOIN AppointmentStudent as ON s.studentID = as.studentID
INNER JOIN Appointment a ON as.appointmentID = a.appointmentID
INNER JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
WHERE s.studentID = #studentID
GROUP BY col1, col2
) t
The aggregate columns summarizes appointments into the weeks of the year, but it only does sos for the weeks the student had appointments. I have an additional table called SchoolWeekYear that is populated with all of the weeks of the year that I am trying to integrate to this proc so I get 52 records back and not just the handful I am currently getting.
SELECT col1, col2
FROM (
col1, col2
SELECT col3--aggregate columns
FROM iep i
INNER JOIN student s ON s.studentID = i.studentID
INNER JOIN dbo.IDuration id ON i.IepID = id.iepID
INNER JOIN AppointmentStudent as ON s.studentID = as.studentID
INNER JOIN Appointment a ON as.appointmentID = a.appointmentID
LEFT OUTER JOIN SchoolWeekYear swy on a.calWeekNumber = swy.calWeekNumber
INNER JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
WHERE s.studentID = #studentID
GROUP BY col1, col2
) t
Is this possible?
You need to integrate SchoolWeekYear into the existing table set at an earlier stage.
To show you the principle, let us simplify the problem even further. Let there be a table called WeeklyData with columns WeekNumber and SomeData. Some weeks might have multiple entries, some others none. So this query
SELECT
WeekNumber,
AGG(SomeData)
FROM
WeeklyData
GROUP BY
WeekNumber
;
would return only weeks present in WeeklyData. If you want to return data for all weeks, use a corresponding reference table (let it be called AllWeeks) like this:
SELECT
aw.WeekNumber,
AGG(wd.SomeData)
FROM
AllWeeks AS aw
LEFT JOIN
WeeklyData AS wd ON aw.WeekNumber = wd.WeekNumber
GROUP BY
aw.WeekNumber
;
So, you take the reference table (AllWeeks) and join the data table (WeeklyData) to it, not the other round.
Now, what if the original query was slightly more complex? Let us now suppose the data table is called StudentWeeklyData and has a column called StudentID which is a reference to a Students table. Let us also imagine the query is similar to yours in that it logically includes the Students table before the data table is joined and filters the results on the primary key of Students:
SELECT
s.StudentID,
s.StudentName,
swd.WeekNumber,
AGG(swd.SomeData)
FROM
Students AS s
INNER JOIN
StudentWeeklyData AS swd ON s.StudentID = swd.StudentID
WHERE
s.StudentID = #StudentID
GROUP BY
s.StudentID,
s.StudentName,
swd.WeekNumber
;
(Not every detail matters here, I just wanted to use a more similar example for you that would still be simple enough to understand.) Again, this would return only weeks where the specified student has data in StudentWeeklyTable. If you wanted to return all weeks for the student (some of them potentially empty, of course), this is how you could go about it:
SELECT
s.StudentID,
s.StudentName,
aw.WeekNumber,
AGG(swd.SomeData)
FROM
Students AS s
CROSS JOIN
AllWeeks AS aw
LEFT JOIN
StudentWeeklyData AS swd ON s.StudentID = swd.StudentID
AND aw.WeekNumber = swd.WeekNumber
WHERE
s.StudentID = #StudentID
GROUP BY
s.StudentID,
s.StudentName,
aw.WeekNumber
;
Here you can see again that the AllWeeks table is included before the data table. The difference to the previous case is we are not left-joining the result of the join between Students and StudentWeekly to AllWeeks, nor are we left-joining the data table itself specifically to AllWeeks. Instead, the data table is joined to the result of a cross join, Students × AllWeeks.
Returning to your specific situation, I realise that in your case even more tables are involved. Since you are not specifying how all those tables are related to one another, I can only guess that SchoolWeekYear should be cross-joined somewhere after FROM and before this line:
INNER JOIN Appointment a ON as.appointmentID = a.appointmentID
and that the said line should be modified like this:
LEFT JOIN Appointment a ON as.appointmentID = a.appointmentID
AND swy.calWeekNumber = a.calWeekNumber
the swy being an alias assigned to SchoolWeekYear.
It is also worth noting that there is a subsequent inner join with AppointmentTherapist. That join would eliminate the effect of the above left join if it remained unchanged, because its condition references the Appointment table. Perhaps, the syntactically easiest way to fix the issue would be to change that inner join to a left one too, although there is another way: instead of
LEFT JOIN Appointment a ON as.appointmentID = a.appointmentID
AND swy.calWeekNumber = a.calWeekNumber
LEFT JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
you could use this syntax:
LEFT JOIN
Appointment a
INNER JOIN AppointmentTherapist at ON a.appointmentID = at.appointmentID
ON as.appointmentID = a.appointmentID
AND swy.calWeekNumber = a.calWeekNumber
That way the logical order of joining would be changed: Appointment and AppointmentTherapist would be first inner-joined with each other, then the result set would be outer-joined to the result of the previously specified joins.
It is possible. But if you have multiple row with some calWeekNumber on the SchoolWeekYear table, your aggregate function return wrong result.
If you want all lines in SchoolWeekYear shown, regardless of a match, you should use RIGHT OUTER JOIN instead of LEFT.

Counting grouped records from multiple tables

there is a column comment_id of a table called pic_alb_love which i'd like to add to the query below but i don't know how. Actually what i want to do is to count the total comment_id of the table pic_alb_love.
SELECT users_pics.wardrobe,
profile.fname,
users_pics.pic,
users_pics.u_pic_id,
users_pics.email,
users_pics.make,
users_pics.designer,
photo_comment.comment,
max_photo_comment.count_pic_id
FROM dbo.users_pics
INNER JOIN profile
ON users_pics.email = profile.email
LEFT Join (SELECT pic_id
,MAX(comment_id) max_comment_id
,COUNT(pic_id) count_pic_id
FROM photo_comment
GROUP BY pic_id
) max_photo_comment
On users_pics.u_pic_id = max_photo_comment.pic_id
LEFT Join photo_comment
On max_photo_comment.pic_id = photo_comment.pic_id
AND max_photo_comment.max_comment_id = photo_comment.comment_id
WHERE users_pics.wardrobe = MMColParam
AND users_pics.email = MMColParam2
ORDER BY u_pic_id asc
these are the various fields of the table pic_alb_love:
(comment_id,pic,love_com, wardrobe, email
,com_name,resp_email, play_count, com_stat)
LEFT JOIN (SELECT Pic
,Count(*) [CommentCount]
FROM pic_alb_love
GROUP BY Pic) c
ON c.Pic=u_pic_id
Assuming that pic_alb_love.pic is the FK on the table...
Use [CommentCount] in the select list.

multiple joined query with propel

Let's consider following tables:
special_product(
id
product_key - FK to product.key)
product(
id
key
name)
product_attributes(
id
product_id FK to product.id
description
)
My question is how could I write a query that would provide me columns special_product.id, product.id, product_attributes.description starting from the SpecialProductQuery class.
Basically the generated query should be
select s.id, p.id, pa.description
from special_product s
left join product p on s.key = p.key
left join product_attributes pa on p.id = pa.product_id
Assuming that you've got the relationships build out in your schema you should just be able to do:
$specialProduct = specialProductQuery::create()
->joinWithProduct(SpecialProduct.Product)
->joinWith(Product.ProductAttributes)
->find();
From here you can get whichever of the values you need from the sub-objects (keep in mind you still need to iterate through the collection):
foreach($specialProduct as $special)
{
$product = $special->getProduct();
}
YMMV depending on how you've named out your model.

LINQ entity from database view with MANY to MANY relation

i have a problem. I have a database view with many to many relation, it looks like this
SELECT TOP (100) PERCENT dbo.PostAdditional.Description, dbo.PostAdditional.Summary, dbo.PostAdditional.Title, dbo.Post.PostID, dbo.Post.Type, dbo.Tags.TagID, dbo.Tags.TagName,
FROM dbo.Post
INNER JOIN dbo.PostAdditional ON dbo.Post.PostID = dbo.PostAdditional.PostID
INNER JOIN dbo.PostWithTags ON dbo.Post.EventID = dbo.PostWithTags.PostID
INNER JOIN dbo.Tags ON dbo.PostWithTags.TagID = dbo.Tags.TagID
ORDER BY dbo.Post.StartDate, dbo.Post.PubDate
I want to use LINQ to SQL to work with it. When I normaly put this view in DBML designer, it creates an entity. But entity has proterty TagName as String, and I want it as array of tag names (or better List<>). When I take data from database, i get one copy of Post entity for evry single tag, but I want to get one Post entity with array of all tags associated.
Maybe this will help:
I changed this join from
INNER JOIN dbo.PostWithTags ON dbo.Post.EventID = dbo.PostWithTags.PostID
To
INNER JOIN dbo.PostWithTags ON dbo.Post.PostID = dbo.PostWithTags.PostID
And if I understand you right is this what you want?
var test=
(
from p in db.Post
orderby p.StartDate,p.PubDate
select new
{
p.PostID,
p.Type,
Tags=
(
from pa in db.PostAdditional
join pwt in db.PostWithTags
on pa.PostID equals pwt.PostID
join t in db.Tags
on pwt.TagID equals t.TagID
where p.PostID == pa.PostID
select new
{
pa.Description,
pa.Summary,
pa.Title,
t.TagID,
t.TagName
}
)
}
).ToList();
Where db is the databasecontext

Resources