how to set the sql output unique? [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Unexpected database output when using INNER JOIN
hello i have a sql query like this:
SELECT DISTINCT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID, ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM RAZUORDNUNG rz
right join RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
right join RAUM r ON rz.RAUM_ID = r.ID
WHERE ....
i write the results in a list:
strasseObject.Add(new RAUM()
{
RaumName = rdr["BEZEICHNUNG"].ToString(),
RaumID = rdr["ID"].ToString(),
RaumAttribute = rdr["raumBEZEICHNUNG"].ToString(),
RaumAttributeID = rdr["raumID"].ToString()
});
and the output look like this
<RAUM>
<RaumName>Small Business Room</RaumName>
<RaumID>219</RaumID>
<RaumAttribute>A7OVERHEAD</RaumAttribute>
<RaumAttributeID>168876</RaumAttributeID>
</RAUM>
<RAUM>
<RaumName>Small Business Room</RaumName>
<RaumID>219</RaumID>
<RaumAttribute>Beamer</RaumAttribute>
<RaumAttributeID>168847</RaumAttributeID>
</RAUM>
</ArrayOfRAUM>
you can see that i get 2 results with the same "RaumName" but with different "Raumattribute". i want an output like this:
<RAUM>
<RaumName>Small Business Room</RaumName>
<RaumID>219</RaumID>
<RaumAttribute>A7OVERHEAD</RaumAttribute>
<RaumAttributeID>168876</RaumAttributeID>
<RaumAttribute>Beamer</RaumAttribute>
<RaumAttributeID>168847</RaumAttributeID>
</RAUM>
</ArrayOfRAUM>
thanks in advance

Have you tried to start the query on the other end (select from raum)?
SELECT DISTINCT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID, ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM RAUM r
right join RAZUORDNUNG rz ON rz.RAUM_ID = r.ID
right join RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
WHERE ....

Remove rz.RAUMATTRIBUTE_ID column from your query, and than run.... like
SELECT DISTINCT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID, ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM RAZUORDNUNG rz
right join RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
right join RAUM r ON rz.RAUM_ID = r.ID
WHERE ....
Distinct: The DISTINCT keyword can be used to return only distinct (different) values. So, RAUMATTRIBUTE_ID has different values that's why it return 2 rows.

Related

Linq to sql join with multiple "OR" filters

I need to implement this in Linq-to-sql
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s ON c.Room = s.Entry_Bar_Code
OR c.HomeRoom = s.Entry_Bar_Code
WHERE s.id = 1021645
All the research I've done on this says that linq-to-sql can't support an "OR" multiple join, and the suggestions are to instead do two joins like this:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s ON c.Room = s.Entry_Bar_Code
LEFT OUTER JOIN dbo.Lab_Space s2 ON c.HomeRoom = s2.Entry_Bar_Code
WHERE s.id = 1021645
Those aren't actually the same query though as they'll return different results. Short of just putting the raw SQL into my C# program at this point, is there any way to accomplish the above?
Let's start from beginning. If you use WHERE with column from OUTER JOIN table it means that your query:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s ON c.Room = s.Entry_Bar_Code
OR c.HomeRoom = s.Entry_Bar_Code
WHERE s.id = 1021645
is logically equivalent to:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
JOIN dbo.Lab_Space s
ON c.Room = s.Entry_Bar_Code
OR c.HomeRoom = s.Entry_Bar_Code
WHERE s.id = 1021645;
And this could be achieved with CROSS JOIN(pseudocode):
var q = from c in Collector_Capital_Equipment
from s in Lab_Space
where s.id == 1021645
&& (s.Entry_Bar_Code == c.Room || c.HomeRoom == s.Entry_Bar_Code)
select ...
I assume that you really want to generate query:
SELECT DISTINCT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s
ON (c.Room = s.Entry_Bar_Code OR c.HomeRoom = s.Entry_Bar_Code)
AND s.id = 1021645
which could be represented as:
SELECT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s
ON c.Room = s.Entry_Bar_Code AND s.id = 1021645
INTERSECT
SELECT c.*
FROM dbo.Collector_Capital_Equipment c
LEFT OUTER JOIN dbo.Lab_Space s
ON c.HomeRoom = s.Entry_Bar_Code AND s.id = 1021645
And above query could be achieved with LINQ using set operators.
db<>fiddle demo
I don't think I've ever seen someone use an OR clause on a join before. Does MS SQL Server even support that in SQL?
I'd probably just split this off into two queries, to be honest.
SELECT entry_bar_code
FROM dbo.Lab_Space WHERE id = 1021645;
With the result from that being fed into
SELECT DISTINCT *
FROM dbo.Collector_Capital_Equipment
WHERE c.room == <barcode> OR c.homeRoom == <barcode>

LINQ Left Join with multiple ON OR conditions

I'm sorry for telling that I've a little bit weak on LINQ, I always do write SQL query before I start working on the complicated LINQ.
I want to ask that how to convert this SQL Query into LINQ with LEFT JOIN with multiple ON conditons with the OR operator.,
m.MerchandiseId will be use for twice in ON condition
SELECT
*
FROM
Inbox AS i
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS m ON
u.MerchandiseId = m.MerchandiseId
OR
i.ToMerchantId = m.MerchandiseId
WHERE
i.ToCompanyId = 10
OR
i.FromCompanyId = 10
var message = (from i in db.Inbox
join u in db.User on i.FromUserId equals u.UserId
join m in db.Merchandise on u.MerchandiseId equals m.MerchandiseId //here I want to ON i.MerchantId = m.MerchandiseId, but it doesn't allow
where i.ToCompanyId == user.CompanyId || i.FromCompanyId == user.CompanyId
orderby i.CreatedAt descending
group m.MerchandiseId by new { m.MerchandiseId, m.MerchandiseName } into grp
select new
{
MerchandiseId = grp.Key.MerchandiseId,
MerchandiseName = grp.Key.MerchandiseName,
InboxMessage = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.InboxMessage).FirstOrDefault(),
CreatedAt = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.CreatedAt).FirstOrDefault(),
}).ToList();
The bottom LINQ Query I've write for it. However, I just can work on the left join with multiple ON clause in LINQ. Appreciate if someone would help me on this. Thanks!
I don't believe Linq supports the use of the OR operator with multiple columns, but that said, I wouldn't use OR even in SQL as it makes the join's intention unclear and it also obscures where the data originated from - it also isn't immediately clear what happens if there are multiple matches for each column. Instead I would JOIN twice on the different columns and let the projection-clause handle it:
SELECT
*
FROM
Inbox
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS userMerchant ON u.MerchandiseId = userMerchant.MerchandiseId
LEFT OUTER JOIN Merchandise AS inboxMerchant ON Inbox.ToMerchantId = inboxMerchant .MerchandizeId
WHERE
Inbox.ToCompanyId = 10
OR
Inbox.FromCompanyId = 10
This can then be translated into Linq using the LEFT OUTER JOIN approach ( How to implement left join in JOIN Extension method )
Note that if you're using Entity Framework then you don't need to worry about doing any of this at all! Just use Include:
var query = db.Inbox
.Include( i => i.User )
.Include( i => i.User.Merchandise )
.Include i => i.Merchandise )
.Where( i => i.ToCompanyId = 10 || i.FromCompanyId == 10 );

How can I write this query in LINQ

I have this query
SELECT t.NomeTipo, sum(v.QtdProduto)
FROM [dbo].[Vendas] AS V
RIGHT JOIN [dbo].[Produtos] AS P ON V.IdProduto = P.IdProduto
INNER JOIN [dbo].[Tipos] AS T ON P.IdTipo = T.IdTipo
group by t.NomeTipo
order by t.NomeTipo
I have tried this
var queryTipos = from vendas in repositorioVendas.Vendas
join produtos in repositorioProduto.Produtos.DefaultIfEmpty()
on vendas.IdProduto equals produtos.IdProduto
join tipos in repositorioTipo.Tipos
on produtos.IdTipo equals tipos.IdTipo
group vendas by new { tipos.NomeTipo, vendas.QtdProduto }
into novoGrupo
select new
{
NomeTipo = novoGrupo.Key.NomeTipo,
QtdProduto = novoGrupo.Sum(x => x.QtdProduto)
};
With this query I got only two results, but when I run straight from the database I get something like this:
Bebidas 16
Bolos 14
Frios 16
Pães 21
The trick is to realize that you can rewrite your query with a left join instead of a right join by swapping the order of the first two tables and that Linq doesn't have a way to really handle right joins. Also you're grouping was wrong.
var queryTipos = from produtos in repositorioProduto.Produtos
join vendas_pj in repositorioVendas.Vendas
on vendas_pj.IdProduto equals produtos.IdProduto into joined
from vendas in joined.DefaultIfEmpty()
join tipos in repositorioTipo.Tipos
on produtos.IdTipo equals tipos.IdTipo
group vendas by tipos.NomeTipo
into novoGrupo
select new
{
NomeTipo = novoGrupo.Key,
QtdProduto = novoGrupo.Sum(x => x.QtdProduto)
};
Basically a Left join in SQL
From TableA
Left Join TableB
On TableA.ID = TableB.ID
is done in Linq like this
from a in repo.TableA
join b_pj in repo.TableB
on a.ID equals b_pj.ID into joined
from b in joined.DefaultIfEmpty()

Entity Framework Query for inner join

What would be the query for:
select s.* from Service s
inner join ServiceAssignment sa on sa.ServiceId = s.Id
where sa.LocationId = 1
in entity framework?
This is what I wrote:
var serv = (from s in db.Services
join sl in Location on s.id equals sl.id
where sl.id = s.id
select s).ToList();
but it's wrong. Can some one guide me to the path?
from s in db.Services
join sa in db.ServiceAssignments on s.Id equals sa.ServiceId
where sa.LocationId == 1
select s
Where db is your DbContext. Generated query will look like (sample for EF6):
SELECT [Extent1].[Id] AS [Id]
-- other fields from Services table
FROM [dbo].[Services] AS [Extent1]
INNER JOIN [dbo].[ServiceAssignments] AS [Extent2]
ON [Extent1].[Id] = [Extent2].[ServiceId]
WHERE [Extent2].[LocationId] = 1
In case anyone's interested in the Method syntax, if you have a navigation property, it's way easy:
db.Services.Where(s=>s.ServiceAssignment.LocationId == 1);
If you don't, unless there's some Join() override I'm unaware of, I think it looks pretty gnarly (and I'm a Method syntax purist):
db.Services.Join(db.ServiceAssignments,
s => s.Id,
sa => sa.ServiceId,
(s, sa) => new {service = s, asgnmt = sa})
.Where(ssa => ssa.asgnmt.LocationId == 1)
.Select(ssa => ssa.service);
You could use a navigation property if its available. It produces an inner join in the SQL.
from s in db.Services
where s.ServiceAssignment.LocationId == 1
select s

Unexpected database output when using INNER JOIN

I have the following SQL query
SELECT
r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID,
ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM
RAUM r
INNER JOIN RAZUORDNUNG rz ON rz.RAUM_ID = r.ID
INNER JOIN RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
WHERE
RAUMKLASSE_ID = ISNULL(#Raumklasse_ID, RAUMKLASSE_ID)
AND STADT_ID = ISNULL(#Stadt_ID, STADT_ID)
AND GEBAEUDE_ID = ISNULL(#Gebaeude_ID, GEBAEUDE_ID)
AND REGION_ID = ISNULL(#Region_ID, REGION_ID)
AND RAUMATTRIBUTE_ID = ISNULL(#Raumattribute_ID, RAUMATTRIBUTE_ID)
But I think that something is wrong with that.
For example:
If I put three in the RAUMKLASSE_ID textfield in the browser and invoke my method it returns only one room. But there are six rooms with that ID. The strange thing is, that if I remove the two INNER JOIN and the second line of my SELECT, like this:
SELECT
r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID
FROM
RAUM r
WHERE
RAUMKLASSE_ID = ISNULL(#Raumklasse_ID, RAUMKLASSE_ID)
AND STADT_ID = ISNULL(#Stadt_ID, STADT_ID)
AND GEBAEUDE_ID = ISNULL(#Gebaeude_ID, GEBAEUDE_ID)
AND REGION_ID = ISNULL(#Region_ID, REGION_ID)
AND RAUMATTRIBUTE_ID = ISNULL(#Raumattribute_ID, RAUMATTRIBUTE_ID)
it is returning the six rooms, which is correct. I don't know what the problem is with my query. Maybe someone can help me with that?
Thanks in advance
This is the expected behaviour, since:
FROM RAUM r
INNER JOIN RAZUORDNUNG rz ON rz.RAUM_ID = r.ID
INNER JOIN RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
Will get you only the rooms that are found in the tables RAUM, RAZUORDNUNG and RAUMATTRIBUTE tables, removing these INNER JOINs will get you all the rooms from the RAUM table that satisfy your condition, check these pages for more details about JOINs:
A visual explanation for JOINs.
Wikipedia article about JOINs
INNER JOIN won't return RAUM entries that have no corresponding RAZUORDNUNG or RAUMATTRIBUTE. You may need a LEFT JOIN instead; in this case, raumBEZEICHNUNG and raumID may be null in the returned set.

Categories