JOIN for Membership table - asp.net

Why Microsoft uses stupid examples with GroupBy clause only for one table?
http://msdn.microsoft.com/en-us/library/bb896341.aspx
And why error is causing when i tried to Select some field that is not in GroupBy?
Error says that fields that is not in GroupBy clause doesn't exist in current context.
using (Entities db = new Entities())
{
var query = "SELECT RLS.RoleId, UIR.UserId, UIR.RoleId, USR.UserName FROM Entities.aspnet_Roles AS RLS " +
"INNER JOIN Entities.vw_aspnet_UsersInRoles AS UIR " +
"ON RLS.RoleId = UIR.RoleId " +
"INNER JOIN Entities.aspnet_Users AS USR " +
"ON UIR.UserId = USR.UserId " +
//"GROUP BY RLS.RoleId" // is uncomment - it says UserId doesn't exist in context
;
var x = new ObjectQuery<DbDataRecord>(query, db);
var y = x.ToTraceString().Replace("\n", " ").Replace("\t", " ").Replace("\r", " ");
}
The same for LINQ:
var x = from RLS in db.aspnet_Roles
join URS in db.vw_aspnet_UsersInRoles
on RLS.RoleId equals URS.RoleId
join USR in db.aspnet_Users
on URS.UserId equals USR.UserId
group RLS by RLS.RoleId into GRP
select new
{
GRP.Key
};
The question is: how to select all fields and GroupBy selection by only one field?
Thanks in advance.

All fields that are not in the GROUP BY clause have to be aggregate expressions such as AVG(...) or SUM(...) or MAX(...) etc.
So this is wrong:
SELECT RLS.RoleId, UIR.UserId, UIR.RoleId, USR.UserName
(...)
GROUP BY RLS.RoleId
because the last three expressions in the SELECT should either be aggregated somehow or added to the GROUP BY clause.
This is logical because by specifying GROUP BY RLS.RoleId you say that RLS.RoleId should be unique in the end result, so only one row per value. But for each RLS.RoleID there could be multiple values for UIR.UserId, UIR.RoleId or USR.UserName. So you need to tell the DBMS what to do to make them into one row: average, maximum, minimum... OR you add fields to the GROUP BY clause, so that not RLS.RoleID but the combination of column values should be unique. See also this example.

I don't see any aggregate functions (COUNT, SUM, AVG, etc) being used in the query you posted. Thus, there's no need to include a GROUP BY expression, and there's really no reason to do so. Could you please explain what you're trying to accomplish?

I think i didn't understand littlegreen.
His advice really helped ... though i was upset by SQL Server comparing to MySQL (there is enough to set one grouping field).
Works!
SELECT DISTINCT
RLS.RoleId,
COUNT(RLS.RoleId) AS RID_CNT,
MAX(CAST(UIR.UserId AS VARCHAR(36))) AS EXPR1,
MAX(CAST(USR.UserName AS VARCHAR(36))) AS EXPR2
FROM aspnet_Roles AS RLS
INNER JOIN vw_aspnet_UsersInRoles AS UIR ON RLS.RoleId = UIR.RoleId
INNER JOIN aspnet_Users AS USR ON UIR.UserId = USR.UserId
GROUP BY RLS.RoleId

Related

EF Core - Count from a specific column

I almost have my EF Core query working... This is the SQL getting produced (notice the Count(*):
SELECT [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn], COUNT(*) AS [Clicks]
FROM [URLs] AS [u]
LEFT JOIN [OwnerUrls] AS [o] ON [u].[Key] = [o].[ShortUrlKey]
LEFT JOIN [Clicks] AS [c] ON [u].[Key] = [c].[ShortUrlKey]
GROUP BY [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn]
What I need is (have Count look at a specific column/table)
SELECT [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn], COUNT(c.ID) AS [Clicks]
FROM [URLs] AS [u]
LEFT JOIN [OwnerUrls] AS [o] ON [u].[Key] = [o].[ShortUrlKey]
LEFT JOIN [Clicks] AS [c] ON [u].[Key] = [c].[ShortUrlKey]
GROUP BY [u].[Key], [u].[Url], [u].[CreatedBy], [u].[CreatedOn]
Here is the EF Query that I'm using...
query = (from u in db.URLs
join ou in db.OwnerUrls on u.Key equals ou.ShortUrlKey into urlOwners
from subSet in urlOwners.DefaultIfEmpty()
join c in db.Clicks on u.Key equals c.ShortUrlKey into urlClicks
from subClicks in urlClicks.DefaultIfEmpty()
group subClicks by new { u.Key, u.Url, u.CreatedBy, u.CreatedOn } into g
select new ShortURL()
{
Key = g.Key.Key,
Url = g.Key.Url,
CreatedBy = g.Key.CreatedBy,
CreatedOn = g.Key.CreatedOn,
Clicks = g.Count()
});
I've tried changing the g.Count() to g.Select(x=>x.Id).Count() and that just causes EF Core to barf and complain about client side evaluation vs server side evaluation etc..
I should mention that the reason I'm joining the first model (OwnerUrls) is to support a where clause that I didn't include here...
Thanks!
I'm not a EF developer, but have worked with SQL Server for a while now. In SQL Server i would use COUNT(DISTINCT c.ID) to eliminate any duplicates you might get from JOINS.
If duplicates are impossible due to the model the COUNT(*) shoud be sufficient.
Maybe this might help:
https://entityframeworkcore.com/knowledge-base/51892585/linq-select-distinct-count-performed-in-memory

selecting only max clause without group by properties in subquery using Nhibernate

I have SQL query like this:
select * from dbo.table1 where Id in
(
select max(id) as id from dbo.table1 group by prop1, prop2, prop3
)
I want to create NHibernate query which is be able to do this for me. I tried to use QueryOver but it doesn't work. Do you have any suggestions how to do it?
NHibernate supports even this kind of queries. Please, see more in documentation: 15.8. Detached queries and subqueries. We just have to split the query (as in your SQL snippet) into two parts:
inner select
the select with the IN clause
Let's assume, that the dbo.table1 in the Questin is mapped into MyEntity.
To create inner select, let's use the DetachedCriteria
EDIT (extended with the Group by, SqlGroupProjection)
There is an extract of the SqlGroupProjection method:
A grouping SQL projection, specifying both select clause and group by
clause fragments
// inner select
DetachedCriteria innerSelect = DetachedCriteria
.For(typeof(MyEntity))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.SqlGroupProjection(
" MAX(ID) ", // SELECT ... max(ID) only
" Prop1, Prop2, Prop3", // GROUP BY ... property1, p2...
new string[] {"ID"}, // could be empty, while not used for
new IType[] { NHibernate.NHibernateUtil.Int32 } // transformation
)
)
;
Note: I've provided even the last two paramters, but in this case they could be empty: new string[], new IType[] {}. These are used only for Transformation (materialization from data into entity). And this is not the case, we are just building inner select...
// the select with IN clause
var result = session.CreateCriteria(typeof(MyEntity))
.Add(Subqueries.PropertyIn("ID", innerSelect))
.List<MyEntity>();
Also related could be 15.7. Projections, aggregation and grouping

LINQ - EF join difficulty

I have two tables:
Phase :
long ID
string Name
and another Activity :
long ID
string Name
long PhaseID
I already know the name of the phases and I want to get the activity for those particular phases. Do i add PhaseName to the activity table or do I do it through join in LINQ?
Maybe something like this?
var query = from a in entities.Activities
join p in entities.Phases on a.PhaseId equals p.Id
where p.Name == "Preplanning"
... and here im not sure how to finish this query..
Thanks for your help!
The code that you've provided will use an Inner Join to find all Activities where the Phase with Name "Preplanning" exists.
To finish your query you need to add a select clause.
var query = from a in entities.Activities
join p in entities.Phases on a.PhaseId equals p.Id
where p.Name == "Preplanning"
select a.Name
will return IEnumerable<string> of all activity names.
Just select activity, as you want:
var query = from a in entities.Activities
join p in entities.Phases on a.PhaseId equals p.Id
where p.Name == "Preplanning"
select a;
Here is how query expression should look like:
A query expression must begin with a from clause and must end with a select or group clause. Between the first from clause and the last select or group clause, it can contain one or more of these optional clauses: where, orderby, join, let and even additional from clauses. You can also use the into keyword to enable the result of a join or group clause to serve as the source for additional query clauses in the same query expression.
Same as puzzling image:
With method syntax you don't need to end query with something special:
var query = entities.Phases
.Where(p => p.Name == "Preplanning")
.Join(entities.Activities, p => p.Id, a => a.PhaseId, (p,a) => a);
No need to do a join if you only need data from one of the tables. You can apply a filter instead:
var q = entities.Activities.Where(a =>
entities.Phases.Any(p => a.PhaseId == p.Id && p.Name == "Preplanning"));

SQLite/JDBC inner join

I have found what appears to be a bug in the SQLite JDBC driver, but I thought I'd see if someone could spot any boneheaded errors on my part. I have the following query:
SELECT
SKU_ATTR_VALUE.*,
Product.ProductID
FROM
SKU_ATTR_VALUE
INNER JOIN SKU
ON SKU_ATTR_VALUE.SkuID=SKU.SkuID
INNER JOIN Product
ON SKU.ProductID=Product.ProductID
WHERE Product.ProductID=?
Pretty simple. I can run this in the SQLite database browser, replacing the ? with 1, and it returns 18 rows, which is just what it should do. Only 18 rows match the condition. But when I run this in Java, and pass in the value 1, I get 817 values back. And that's not a Cartesian join; there are 864 possible values in SKU_ATTR_VALUE. The results I get back have at least one value for each record in Product too...so I really can't imagine what is happening.
I've been looking at this a while and I'm completely stumped. Googling it doesn't seem to turn anything up. Yes, I'm sure that I'm running the Java query against the same SQLite database as in the SQLite browser.
The name of the SQLite jar is sqlitejdbc-v056.jar. It is based on SQLite 3.6.14.2.
Here is the Java code that sets up the query:
String sql = "SELECT SKU_ATTR_VALUE.*, Product.ProductID " +
"FROM SKU_ATTR_VALUE " +
" INNER JOIN SKU ON SKU_ATTR_VALUE.SkuID=SKU.SkuID " +
" INNER JOIN Product ON SKU.ProductID=Product.ProductID " +
"WHERE Product.ProductID=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, productID);
ResultSet rs = ps.executeQuery();
According to this document section "5.0 Joins" : you can try to rewrite your query like this :
SELECT
SKU_ATTR_VALUE.*,
Product.ProductID
FROM
Product, SKU, SKU_ATTR_VALUE
WHERE
Product.ProductID=?
AND SKU.ProductID=Product.ProductID
AND SKU_ATTR_VALUE.SkuID=SKU.SkuID

ASP.NET: Linq2SQL: selecting all names matching an id

Got 2 tables: db.Tags (ID, TagName) and db.Names (ID, Name, TagID).
I want to fetch all db.Tags rows, and all the Names matching the TagID.
So it will look like
ID - TagName - Names
1 - tag1 - name1, name2, name3
2 - tag2 - name4, name5, name6
Is this possible in one (long) linq query?
or do I have to get all the tags, then do foreach tag, get all the names, then do foreach names to put them in a one long string..
Thanks in advance!
EDIT:
Okay see my comment on the second answer (first one up..), this is what i tried but i get some errors in compiler:
var tags =
from t in db.Tags
orderby t.Priority ascending
select new {
t.ID,
t.Name,
t.Priority,
Places = String.Join(", ",
(from p in db.Places
join o in db.TagToPlaces on new {
p.ID,
t.ID
}
equals new {
o.PlaceId,
o.TagId
}
select p.Name
).ToArray()
)
}
);
I think this is what you're after:
var query =
from t in db.Tags
select new
{
t.ID,
t.TagName,
Names = String.Join(", ",
(from n in db.Names
where n.TagID == t.ID
select n.Name)
.ToArray()),
};
With this I get the same sort of output that you gave in your question. I also understood that you want to output the tag id and name even when there are no associated name records - my query does that.
Now depending on if you're using EF or LINQ-to-SQL or something else you may need to add .ToArray() to the db.Tags & db.Names references to force the database query to occur.
If you have a large number of tag records you'll find you have a large number of queries going to the database. You could make this change to reduce it to only two queries:
var tags = db.Tags.ToArray();
var names = db.Names.ToArray();
var query =
from t in tags
select new
{
t.ID,
t.TagName,
Names = String.Join(", ",
(from n in names
where n.TagID == t.ID
select n.Name)
.ToArray()),
};
Now you just need to make sure that your data fits into memory - but it sounds like it should. I hope this helps.
Since the concat is a pain in TSQL, I would query the 3 values "as is", and format from there:
var list = (from tag in db.Tags
join name in db.Names
on tag.ID equals name.TagId
orderby tag.ID
select new { tag.ID, tag.TagName, name.Name }).ToList();
for example, if I wanted the names by tag-id, I could do:
var namesByTag = list.ToLookup(row => row.ID, row => row.Name);
(or whatever else you choose)

Resources