LINQ entity from database view with MANY to MANY relation - sql-server

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

Related

Return max of the value in view SQL Server

I created this view as you can see here :
The result of my view is this :
but in fact I need two values: the max record of fitupdetailid and `weldetaildid.
I am new to SQL query. Can I add some filter to my view?
SELECT
dbo.fitupdetail.fitupdetailId, dbo.jointId.JointId,
dbo.weldDetail.WeldDetailId
FROM
dbo.weldDetail
INNER JOIN
dbo.jointId ON dbo.weldDetail.jointid = dbo.jointId.JointId
INNER JOIN
dbo.fitupdetail ON dbo.jointId.JointId = dbo.fitupdetail.jointid
I mean
101-2-51
201-1-1002
Try like this,
Using view:
select jointid,max(fitupdetailid),max(weldetaildid) from <yourviewname>
group by jointid
Using SQL:
SELECT
MAX(dbo.fitupdetail.fitupdetailId), dbo.jointId.JointId,
MAX(dbo.weldDetail.WeldDetailId
FROM
dbo.weldDetail
INNER JOIN
dbo.jointId ON dbo.weldDetail.jointid = dbo.jointId.JointId
INNER JOIN
dbo.fitupdetail ON dbo.jointId.JointId = dbo.fitupdetail.jointid
GROUP BY dbo.jointId.JointId

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;

MS SQL Table Joins - Multiple Tables

I am new to MS SQL and am having trouble joining 4 tables within a query.
I am trying to join Orders, Order Lines, Client, and Picked tables to create a query to show quantity ordered and picked for a client. If I comment out the last inner join for Picked, I get the correct results. When I include the inner join for Picked the query returns results but data that should be in the Picked fields is NULL. One order line can have 1 or more Picked lines.
SELECT W_Warehouse, OH.OrderID, OH.RequiredDate, C.Client, OL.LineNbr, OL.QtyOrd, P.QtyPick
FROM Order
INNER JOIN Warehouse on Order.OH_WHS = Warehouse.W_PK
INNER JOIN Client on Order.O_Client = Client.C_PK
INNER JOIN OrderLine on Order.O_PK = OrderLine.OL_PK
INNER JOIN Picked on OrderLine.O_PK = Picked.P_PK
WHERE C.CLIENT = 'WENDYS'
Without knowing the data in the tables it is difficult to answer precisely.
But as you say you have 1+ rows in the Picked table, you probably want to do aggregation with GROUP BY and SUM()
Maybe this is what you're looking for:
SELECT
W.W_Warehouse,
OH.OrderID,
OH.RequiredDate,
C.Client,
OL.LineNbr,
OL.QtyOrd,
P.QtyPick
FROM
Order OH
INNER JOIN Warehouse W on OH.OH_WHS = W.W_PK
INNER JOIN Client C on OH.O_Client = C.C_PK
INNER JOIN OrderLine OL on OH.O_PK = OL.OL_PK
CROSS APPLY (
select sum(QtyPick) as QtyPick
from Picked P
where OL.O_PK = P.P_PK
) P
WHERE
C.CLIENT = 'WENDYS'
It calculates the sum of QtyPick separately so it doesn't increase the number of lines in the result.

mssql and dynamic column from another table

i have this select statement:
select * from folder
inner join subprops on folder.id = subprop.id
inner join props on props.id = subprops.id
inner join products on product.feature = subprop.val
product.feature has values for example 300,301
and subprop.val has these values as well
i have column props.colname
and i want to make the third inner join dynamicly by the props.colname value
with some kind of eval() or anything else
inner join products on product.eval(props.colname) = subprop.val
can you think about anything? i can't find solution for that without dynamic statement or loop - that i don't want to do

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.

Resources