Linq-sql join two tables - linq-to-sql

I'm trying to join two tables in my database based off two values that exist in both tables (model and manufacturer), there is no fk relationship in the database for these values for various reasons.
So far I have the following:
var modelManufacturer = DataContext.Assets_ND.Select(a => new {a.ModelNo, a.Manufacturer}).Distinct();
var masterPMs = DataContext.MasterPlannedMaintenances.Where(pm => pm.PlantId == model.PlantId);
var joined = modelManufacturer.Join(masterPMs.AsEnumerable(), a => new {a.ModelNo, a.Manufacturer},pm => new {pm.Model, pm.Manufacturer}, x => new {x.ModelNo, x.Manufacturer, x.Id});
This doesn't compile and has the error
Error 7 The type arguments for method
'System.Linq.Queryable.Join(System.Linq.IQueryable,
System.Collections.Generic.IEnumerable,
System.Linq.Expressions.Expression>,
System.Linq.Expressions.Expression>,
System.Linq.Expressions.Expression>)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
This is where I'm a bit stumped as to how to specify the values, I've tried a few combinations of
modelManufacturer.Join<Asset, MasterPlannedMaintenance....> but intellisense seems to suggest that isnt right, or at least the order I'm putting them in isn't corrrect.
What am I doing wrong or what is a better way to join these two tables based on two string fields and return 2 values from the left table (Model, Manufacturer) and one from the right (id).

var joined = (from a in dc.table1
join b in dc.table2 on a.id equals b.id into temp
from t in temp.DefaultIfEmpty()
select new {
a.Model,
a.Manufacturer,
t.ID
});
This will do a left join on the two tables and only select two values from table1 and 1 from table 2.

Related

Different result for #SQLResultSetMapping+Joins on multiple entities | JPA

I am running a NativeQuery with JPA that gives different results compared to running the query in an sql tool. Probably I missunderstand s.th. within the concept of #SQLResultSetMapping.
--- Overview ---
I am mapping the result to two entities, so I am expecting to receive a List of Entity-Pairs. This works.
When you look at the picture below, you'll see the result of the query in an sql tool, where ..
.. the RED BOX maps to one entity
.. the GREEN BOX maps to the second entity
JPA should give me one of the native row as a pair of two entities.
Problem
This is where things go wrong. Yes, I will receive a list of pairs of both entities, but unlike in the picture the column "pp.id" does not iterate over all rows of the respective table (in the picture "5,6,7,..", from JPA "5,5,5,5,..").
The column pp.id is a joined column, I guess that I missunderstand something within JPA when it comes to Joins + SQLResultSetMappings. It appears to me that the difference is that JPA is always joining THE SAME row from table 'propertyprofile' (more detailes below), unlike when the query is run in sql.
I hope that somebody takes pity on me and helps me out. :)
--- Details ---
Query
I am basically trying to find out if every 'product', has defined a 'value' (table propertyvalue) for a predefined 'property' (table propertyprofile).
The probably most relevant part is at the bottom, where "propertyprofile" is joined and "propertyvalue" is left-joined.
select sg.ID as 'sg.id', sg.Name as 'sg.name', ppcount.totalppcount as 'sg.totalppcount', ppcount.totalppothercount as 'sg.totalppothercount',
p.ID as 'product.id', pp.id as 'pp.id', pp.Role as 'pp.role', pp.Name as 'pp.name',
(case when pv.id is null then '0' else '1' end) as 'hasPropertyValue', pv.ID as 'pv.id', pv.StringValue, pv.IntervallMin, pv.IntervallMax
from shoppingguide sg
join
(
select sg.ID as 'sgid', count(*) as 'totalppcount', count(pp_other.ID) as 'totalppothercount' from propertyprofile pp_all
left join propertyprofile pp_other on pp_other.id = pp_all.id AND pp_other.Role = '0'
join shoppingguide sg on pp_all.ShoppingGuideID = sg.ID
join shopifyshop ss on sg.ShopifyShopID = ss.ID
where
pp_all.ShoppingGuideID = sg.ID AND
ss.Name = :shopName
GROUP BY pp_all.ShoppingGuideID
) ppcount on ppcount.sgid = sg.id
join shopifyshop ss on sg.ShopifyShopID=ss.ID
join product p on p.ShopifyShopID = ss.ID
join propertyprofile pp on (pp.ShoppingGuideID = sg.id AND pp.Role = '0')
left join propertyvalue pv on (pv.ProductID=p.ID and pv.PropertyProfileID = pp.id)
where
ss.Name = :shopName
order by sg.id asc, p.id asc, pp.id asc
;
Tables
There are a lot of tables involved, but these are the most important ones to understand the query:
product
propertyprofile - a feature that all products have (e.g. height, price)
propertyvalue - data for a specific feature; relates to propertyprofile (e.g. 5cm; $120)
SQLResultSetMapping
The mapping is done onto two entites: ProductDataFillSummary_ShoppingGuideInformation, ProductDataFillSummary_ProductInformation.
#SqlResultSetMapping(
name = "ProductDataFillSummaryMapping",
entities = {
#EntityResult (
entityClass = ProductDataFillSummary_ShoppingGuideInformation.class,
fields = {
#FieldResult(name = "shoppingGuideId", column = "sg.id"),
#FieldResult(name = "shoppingGuideName", column = "sg.name"),
#FieldResult(name = "numberOfTotalPropertyProfiles", column = "sg.totalppcount"),
#FieldResult(name = "numberOfTotalPropertyProfilesOther", column = "sg.totalppothercount")
}),
#EntityResult(
entityClass = ProductDataFillSummary_ProductInformation.class,
fields = {
#FieldResult(name = "productID", column = "product.id"),
#FieldResult(name = "propertyProfileId", column = "pp.id"),
#FieldResult(name = "propertyProfileRole", column = "pp.role"),
#FieldResult(name = "propertyValueId", column = "pv.id"),
#FieldResult(name = "hasPropertyValue", column = "hasPropertyValue")
}
)
})
Analysis
The problem seems to be that Hibernate does NOT ..
.. process each row
.. per row map onto designated entities
.. put the mapped entities for this row into List (in my example a pair of entities)
In fact hibernate seems to match both entities, which should go into the same entry of List, based on the primary key attributes, i.e. sth like this:
.. process each row
.. for each row map to respective entities (separately)
.. store the mapped entities using their primary key
.. match respective entities which go into the same entry for List
In my example, a pairs of [ProductDataFillSummary_ShoppingGuideInformation, ProductDataFillSummary_ProductInformation] will be inserted into the list. When 'ProductDataFillSummary_ProductInformation' is insterted, Hibernate will try to find the correct instance using the primary key (here 'ProductDataFillSummary_ProductInformation.productId'). Due to several rows for ProductDataFillSummary_ProductInformation having the same value for productId, always the first instance will be fetched and used for List.
Solution
Either use a compound key that considers 'ProductDataFillSummary_ProductInformation.productId' and '.propertyProfileId', or ..
Use an artifical key (uuid) if it's not possible to use a combined key:
concat(p.ID, '-', pp.ID) as 'uuid'

JOIN two sql SELECT statements where one has single record and other has multiple records

I have tow tables, the first is mda_alert_info and the second is key_contacts_info. For each alert set up there may be multiple corresponding contacts. Both tables are linked by 3 columns mda_id, stage_id and ref_number and during the query I will have to pass figures values for them
How do I get all what I want from both tables in one statement. Below are the individual SELECT statements.
$result = mysql_query("SELECT `mda_name`, `project_name`, `ipc_id` FROM `mda_alert_info` WHERE `stage_id`=1 AND `mda_id`=2 AND `ref_number`= '444'");
This will always return one record
$result = mysql_query("SELECT `contact_role`, `contact_email`, `contact_ph_number` FROM `key_contacts_info` WHERE `stage_id`=1 AND `mda_id`=2 AND `role`=0 AND `ref_number`='444'");
This may return multiple records
I tried for a while and couldn't get it to work so I tried adding another field called 'me' to both tables which is basically concatting mda_id and stage_id strings then I tried the query below.
$result = mysql_query("SELECT key_contacts_info.contact_role, key_contacts_info.contact_email, key_contacts_info.contact_ph_number, mda_alert_info.mda_name, mda_alert_info.project_name, mda_alert_info.ipc_id FROM key_contacts_info LEFT JOIN mda_alert_info ON key_contacts_info.me = mda_alert_info.me WHERE stage_id=1 AND mda_id=2 AND role=0 AND ref_number='444'");
But it's still not working. What am I doing wrong and how do I get it to work.
UPDATE:
Sorry but I should clarify something on the relationship between the tables the three columns exist on each table but are not primary keys on either of the tables
SELECT a.*, b.*
FROM mda_alert_info a
INNER JOIN key_contacts_info b
ON a.mda_id = b.mda_id AND
a.stage_id = b.stage_id AND
a.ref_number = b.ref_number
WHERE b.role = 0 AND
a.stage_id = 1 AND
a.mda_id = 2 AND
a.ref_number = '444'
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
select
a.mda_name,
a.project_name,
a.lpc_id,
k.contact_role,
k.contact_email,
k.contact_ph_number
from mda_alert_info a
join key_contacts_info k
on a.state_id = k.state_id
and a.mda_id = k.mda_id
and a.ref_number = k.ref_number
where a.state_id = 1
and a.mda_id = 2
and a.ref_number = '444'
and k.role = 0
;

NHibernate INNER JOIN on a SubQuery

I would like to do a subquery and then inner join the result of that to produce a query. I want to do this as I have tested an inner join query and it seems to be far more performant on MySql when compared to a straight IN subquery.
Below is a very basic example of the type of sql I am trying to reproduce.
Tables
ITEM
ItemId
Name
ITEMRELATIONS
ItemId
RelationId
Example Sql I would Like to create
Give me the COUNT of RELATIONs for ITEMs having a name of 'bob':
select ir.itemId, count(ir.relationId)
from ItemRelations ir
inner join (select itemId from Items where name = 'bob') sq
on ir.itemId = sq.itemId
group by ir.itemId
The base Nhibernate QueryOver
var bobItems = QueryOver.Of<Item>(() => itemAlias)
.Where(() => itemAlias.Name == "bob")
.Select(Projections.Id());
var bobRelationCount = session.QueryOver<ItemRelation>(() => itemRelationAlias)
.Inner.Join(/* Somehow join the detached criteria here on the itemId */)
.SelectList(
list =>
list.SelectGroup(() => itemRelationAlias.ItemId)
.WithAlias(() => itemRelationCountAlias.ItemId)
.SelectCount(() => itemRelationAlias.ItemRelationId)
.WithAlias(() => itemRelationCountAlias.Count))
.TransformUsing(Transformers.AliasToBean<ItemRelationCount>())
.List<ItemRelationCount>();
I know it may be possible to refactor this into a single query, however the above is merely as simple example. I cannot change the detached QueryOver, as it is handed to my bit of code and is used in other parts of the system.
Does anyone know if it is possible to do an inner join on a detached criteria?
MySql 5.6.5 has addressed the performance issue related to the query structure.
See here: http://bugs.mysql.com/bug.php?id=42259
No need for me to change the output format of my NHibernate queries anymore. :)

Loop in MySql, or alternative?

I have a MySql db with innoDB tables. Very simplified this is how two tables are layed out:
Table A:
controlID(PK)
controlText
Table B:
controlOptionID(pk)
controlID(FK to table A)
controlOptionType
controlOptionValue
So many controlOptions(table B) can reference one control(giving that control multiple options). But for each option two rows are made in table B: one row with controlOptionType = "linkToCreator" and controlOptionValue = (an ID to the template it was made from*). And the other row type = "optionSelected" and value = "true"(or false).
= its a pretty complicated setup, but basically instead of set columns we are making dynamic ones by means of the type being what the column would have been called. So I couldnt link to the template with FK.
So now I need to select every control(which will have 2 controlOptions linking to it) where the one controlOptionValue value is true or false(depending on what i need) and the other controlOptionValue is an text ID that I specify.
What I think is the best way to do it is a
SELECT * FROM tableB WHERE controlOptionType = 'linkToCreator'
Then do a loop over that result set saying:
SELECT * FROM tableB WHERE tableB.controlID = (the controlID in this iterations row) AND tableB.controlValue = 'true'
But maybe thatls really inefficient, and either way I have no clue how to do that. It would be great if I could get a single query(i.e. not using stored procedures) that I specified templateID and true or false and it gave me a row result if it didn't find anything.
BTW this is for a search in our application with will need to go through TONS of rows so performance is paramount. And yes, I know the setup isnt the greatest...
Thanks :D
Like this?
SELECT * FROM tableA AS A
LEFT JOIN tableB AS ctrl1 ON (A.controlID = ctrl1.controlID AND ctrl1.controlOptionType = ? AND ctrl1.controlOptionValue = ?)
LEFT JOIN tableB AS ctrl2 ON (A.controlID = ctrl2.controlID AND ctrl2.controlOptionType = ? AND ctrl2.controlOptionValue = ?)
Try this:
SELECT *
FROM Table_A
LEFT JOIN Table_B
ON Table_A.ControlID = Table_B.ControlID
WHERE Table_A.controlOptionType = 'linkToCreator

Linq Group on a multi-level object with select statement

I've got 3 dataset objects that are nested with each other using entity set objects. I am selecting the data like this
var newList = from s in MainTable
from a in s.SubTable1 where a.ColumnX = "value"
from b in a.Detail where b.Name = "searchValue"
select new {
ID = s.ID,
Company = a.CompanyName,
Name = b.Name,
Date = s.DueDate
Colour = b.Colour,
Town = a.Town
};
and this works fine, but the trouble is there are many records in the Detail object-list/table for each Name value so I get a load of duplicate rows and thus I only want to display one record per b.Name. I have tried putting
group s by b.Name into g
before the select, but then this seems to stop the select enabling me to select the columns I want (there are more, in practice). How do I use the group command in this circumstance while still keeping the output rows in a "flat" format?
Appending comment as answer to close question:-
Of course that if you group your results, you cant get select a column of a child, thats because there may be more than one childs and you have to specify an aggregate column for example the sum,max etx –