Why is my code not working as expected? The others (departmentName, employeeName and statusDescription) are working (shown below)
int countRow = 1;
//Query for account status
var query = from emp in db.EmployeeDetails
join stat in db.Status on emp.statusId equals stat.statusId
join dep in db.Department on emp.departmentId equals dep.departmentId
where emp.employeeName == name
select new { emp, stat, dep };
foreach (var q in query)
{
Console.WriteLine("{0,-3} | {1,-10} | {2,10}\t\t | {3,10}",
countRow,
q.dep.departmentName,
q.emp.employeeName,
q.stat.statusDescription);
Console.WriteLine("-----------");
countRow++;// <---------not adding: output keeps printing 1
}
It's working but my countRow is constantly having a value of 1
Right now, my output looks like this:
No. Dep Name Status
1 Finance John Present
1 Education Mary Present
1 Recreational Tom Absent
What I'm looking for is this:
No. Dep Name Status
1 Finance John Present
2 Education Mary Present
3 Recreational Tom Absent
UPDATE:
It appears my "query" (in foreach var q in query) has a count value of 1. I suppose this is the cause of my issue. Does anyone know how I can fix this?
It seems like you're posting the results of multiple queries.
Your original query looks for a specific name (emp.employeeName == name) which yields, probably, a single result. The results you posted have multiple names in them, which means you're running this query more than once (maybe in an enclosing loop?). Each query initializes countRow to 1, so you get the same number every time.
If you had multiple employees with the same name, you'd see numbers other than 1. As the comments suggest, try to find the enclosing loop and move the countRow = 1 initializer there.
Related
I have two tables:
users:
ID Name
----------------
1 Bob
2 Dave
3 Mike
Books:
ID UserId BookName
------------------------
1 1 Cat in Hat
2 1 Happy Birthday
3 1 One Fish
4 2 Goldilocks
5 2 Three Crows
6 3 Hitchhikers
UserId is a key showing which books each user owns
In my html I want to create output that looks like this:
Name Books Owned
-------------------------
Bob Cat in Hat, Happy Birthday, One Fish
Dave Goldilocks, Three Crows
Mike Hitchhikers
Currently I am doing this with a loop and nested query:
var queryusers = db.Query("SELECT * FROM users");
foreach (var user in queryusers) {
<span>#user.name</span>
var querybooks = db.Query("SELECT * FROM books WHERE userid = #0", user.id);
foreach (book in querybooks ) {
<span>#book.bookname</span>
}
}
I know that's not good, but I don't know how to do this with JOIN. If I try:
var queryusersandbooks = db.Query("SELECT * FROM users INNER JOIN books ON users.id = books.userid");
My query returns 6 rows, but I only want 3. Is there a way to do this without having a SQL query in the loop?
Thanks
You are looking for GROUP_CONCAT. Try something like this:
SELECT name AS Name, GROUP_CONCAT(books.bookname SEPARATOR ', ') AS Books
FROM books INNER JOIN users ON users.id=books.userid
GROUP BY books.userid;
Keep in mind that GROUP-CONCAT has a 1024 character limit, so if you need more space, set a bigger threshold before executing the SQL, like this:
SET SESSION group_concat_max_len = 1000000;
SELECT name AS Name, GROUP_CONCAT(books.bookname SEPARATOR ', ') AS Books
FROM books INNER JOIN users ON users.id=books.userid
GROUP BY books.userid;
Here is a working fiddle.
Try something like this
SELECT u.name,CONCAT_WS(',',b.bookname) AS user_books FROM users u INNER JOIN books b ON u.id = b.userid GROUP BY u.id
If I were going to do something like this in mysql, I'd group by user and use group_concat to combine the results:
select users.id, users.name, group_concat(bookname) as books
from users inner join books on books.userid = user.id
group by users.id, users.name
You can order and specify the separator if you like, read about group_concat for more details. This breaks down quickly if there might be a lot of books, or if you want each book to be its own column or anything like that, but it's fine in simple cases.
You are on the right track. In your original code the inner foreach would have executed 6 times as well, once for each of the books.
Using the code below (basing off your own code), the query would still return 6 rows, as you have found, but only prints the user name once.
var queryusersandbooks = db.Query("SELECT * FROM users INNER JOIN books ON users.id = books.userid ORDER BY users.name");
int curruser = 0;
foreach (var userandbook in queryusersandbooks)
{
if (userandbook.userid != curruser)
{
<span>#userandbook.name</span>
curruser = userandbook.userid;
}
<span>#userandbook.bookname</span>
}
I'm trying to write an SQL query where all of a certain group meets a condition.
Update
The Simplifed Table Structure would look like this
ID, TitleID, BlockFromSale
---------------------------
1 | 1 | true
2 | 1 | true
3 | 1 | true
4 | 2 | false
5 | 2 | true
this table would only return the the items TitleID 1.
In actuality I only need the title ID and not the whole item but either will satisfy the conditions.
How Could I write This Linq Query in SQL?
var Query = Data.Items.GroupBy(t => t.TitleID).Where(i => i.All(b => b.BlockFromSale == true));
I try to look at the Sql Query but it just instantly casts it to an object.
Basically I just Need a query that Grabs out all TitleIDs who for each item BlockFromSale is set to true so for the example from the table above it would only return TitleID, 1
It is possible to see the generated SQL of a LINQ query by using the Log property of the query. How to: Display Generated SQL shows an example of this. Basically, the web site shows this example:
db.Log = Console.Out;
IQueryable<Customer> custQuery =
from cust in db.Customers
where cust.City == "London"
select cust;
foreach(Customer custObj in custQuery)
{
Console.WriteLine(custObj.CustomerID);
}
If you want to check predicate p for all rows of a set you can write
NOT EXISTS (... WHERE NOT(p))
Because All(p) == !Any(!p) in pseudo-syntax.
I would guess that ORMs do it this way, too.
There isn't an easy way to do what your asking but a simple but some what slow way would be to use a subQuery
SELECT DISTINCT i.TitleID
FROM Items i
WHERE i.TitleID not in
(SELECT DISTINCT TitleID
FROM items it
WHERE it.BlockFromSale = 0)
so it will remove the titleids who have a false.
I have a Database table like below,
ID Author Book
1 Kate Smuggler
2 Harper Smuggler
3 Slater Smuggler
4 Kate Katy
5 Smitha Katy
i want to retrieve all Book names(Distinct) based on the author name and display them on list view, i wrote the code below to Retrieve distinct values
int UserID = Convert.ToInt32(Session["User"]);
var Li = (from s in Data.TableName where s.Author == UserID select s.Book).Distinct().OrderBy(ID=>ID);
ListViewChatList.DataSourceID = "";
ListViewChatList.DataSource = Li;
ListViewChatList.DataBind();
but i get the following error 'System.String' does not contain a property with the name 'ID'.
How to solve this ?
This part:
select s.Book
is selecting just the book (title) part of the record. You can't get back from that to the ID... there can easily be multiple IDs for the same title, as per your sample data.
It's not clear what you'd want that query to return anyway, given that you're getting distinct book titles - ignoring the author, would you want IDs 1 and 4? 2 and 5? 3 and 5? Both represent the same set of distinct titles (Smuggler and Katy).
You could potentially group by name, and then do whatever you want with the IDs for the books with the shared name - but you really need to consider what your distinctness criterion means for the results.
Here's a query which will give you the lowest ID for each name:
var query = from s in Data.TableName
where s.Author == UserID
group s.ID by s.Book into g
select g.OrderBy(id => id).First();
It's not clear whether that's what you really need though.
var Li = from s in Data.TableName
where s.Author == User
orderby s.ID
select s.Book;
You're only selecting the Book column (a string), and then trying to order by ID, which you no longer have access to, and which certainly is not a property of the Book string.
Assume this is your data:
ID Author Book
1 Kate Smuggler
2 Kate Smuggler2
3 Kate Smuggler
4 Frey Katy
5 Smitha Katy
If you do the following, you'll get the first three books listed above:
(from s in Data.TableName where s.Author == "Kate" select s.Book);
Then you do a distinct, which reduces the books to the two unique ones (Smuggler and Smuggler2):
(...).Distinct();
Then you try to order by the ID, but you didn't originally select it so you don't have access to it. And you've taken a Distinct on the results, so you've lost some of the detail.
Since the two "Smuggler" books have been reduced to one, but their IDs were 1 and 3 (in my example), what should ordering them do? Should the single "Smuggler" book appear before "Smuggler2" or after?
Consider this example data:
field1 field2
1 100
2 100
3 101
4 102
5 102
6 103
I want to select only the records where the value in field2 occurs only once. An example of the desired return data from the above would be:
field1 field2
3 101
6 103
How would this be done with LINQ to SQL?
--- EDIT -------
Hello all, thank you for your responses. I purposely supplied simplified data to get right to the root of my question. I think all these answers return the desired results based on my example data and I will be marking them all answers as such.
however in my real data scenario, using what I've learned from your responses, I have something like this:
var RefinedSource = from a in dSource
group a by a.AssetID into g
where g.Count() == 1
select new
{
AssetID = g.Key,
AssetType = g.Min(a => a.AssetType),
IPInfo = AppUtility.GetIPInfo(g.Key),
Hostname = AppUtility.GetServerName(g.Key),
DeviceID = g.Min(a => a.DeviceID).ToString(),
Environment = AppUtility.GetSolutionAndEnvironmentNames(g.Key),
Manufacturer = g.Min(a => a.Manufacturer),
MakeModel = g.Min(a => a.MakeModel),
Location = g.Min(a => a.Location),
count = g.Count()
};
So I'm concerned about all the .min() calls... I've deduced these are necessary because of the grouping? could someone explain why these are needed? In the case of my simple example I don't see them being an issue, but with my real data there a multiple calls to min() just to be able to include all the field data I need... which doesn't seem good.
The grouping allows me to test the condition I need (that count to identify duplicate values) but how do I more directly use a condition like this but just access my real underlying data rows directly?
for example, looking at the example I just supplied above, I would like to be able to just use a.FieldName from the original "from a in dSource" part, but you can't access that after you have introduced "group by"?
again, thanks for the info, I will be marking as answers, however if anyone could explain the need for all the calls to min() (or max, or whatever) I would appreciate it, also, seeing what it looks like with my real data, is this still the way I should go?
from r in tables
group r.field2 by r.field1 into grp
where grp.Count() == 1
select new {grp.First(), grp.Key}
I'd double check that this does one SQL call. It should, and if so I'd keep it as here because First is a very commonly used Linq method, and when there's a few dozen equally good things to use in a given case one should favour the familiar. If it did cause more than one SQL call (again, I'd be surprised), then try Max() or Min() instead of First().
Here is how it would be done in SQL (sometimes it is faster to use SQL):
SELECT max(field1), field2
FROM table
GROUP BY field2
HAVING count(field2) = 1
Example using window function in sql server
(note, can't test right now the OVER clause might need to be in the where):
SELECT COUNT() OVER(PARTITION BY field2) AS [field2Count], *
FROM table
WHERE [field2Count] = 1
With LINQ you can do simply :
var groups = list.GroupBy(r => r.Value).Where(grp => grp.Count() == 1);
foreach(var gr in groups){
var field1 = gr.Key; // KEY: is your FIELD1
var field2 = gr.Value; // VALUE: is your FIELD2
}
Here is an extract of my query:
...
join p in dc.PODs on c.ID equals p.Consignment into pg
from pgg in pg.DefaultIfEmpty()
...
What the query should do is get all the 'PODs' associated with a consignment, store it as an IEnumerable object (which seems to work) so I can run through it when querying the main IEnumerable generated from the query.
The problem is, I am getting duplicate main rows with the DefaultIfEmpty line, which only happens when a row has multiple PODs - so it's returning a row for each POD, which is incorrect. If I take out the pg.DefaultIfEmpty() line, it seems to work a bit better, but I still want to get the rows without PODs.
Any ideas guys?
Just want to confirm for your 2nd case, wouldn't the output be without the Two, Four, Five which have none item since it is not an outer join?
One
1 TextBox
Three
3 Refridgerator
3 Bucket
What I tried was use an equivalent WHERE IN for dc.PODS.
....join appraisal in ef_appraisal on application.a_appraisalid equals appraisal.a_appraisalid
where
(from r in ..
select r.r_applicationid).Contains(application.a_id) )
Do share if you have other ideas
Forgive me if I'm off on your intention because I can't see the complete structure of your data or your initial from or final select clause in your query excerpt. So I'm posting what I think is a solution based on your snippet and sample data I constructed. Let me know if I'm off and I'll correct it.
If you want a list of rows of consignments to PODs, with each consignment to POD on its own line, you could do something like this (keep in mind my from and select clause are based on my sample data):
// select the consignment id & name (i made up) and each matching POD
var results = from c in consignments
join p in dc.PODs on c.ID equals p.Consignment into pg
from pgg in pg.DefaultIfEmpty()
select new { ID = c.ID, Name = c.Name, POD = pgg };
// This is just a SAMPLE display just for kicks and grins
foreach (var r in results)
{
Console.WriteLine(r.Name + " " + ((r.POD != null)
? (r.POD.Consignment + " " + r.POD.Description)
: "none"));
}
This query outputs something like:
One 1 TextBox
Two none
Three 3 Refridgerator
Three 3 Bucket
Four none
Five none
However I'm not quite sure I understand your remark:
"The problem is, I am getting
duplicate main rows"
I'm not sure if you're saying you don't want to see the one consignment per purchase per row where each result in the IEnumerable is an item with the consignment and a sequence of PODs, you'd want a query like:
// select the Consignment ID and Name (i made up), and list of PODs
// instead of the individual POD
var results = from c in consignments
join p in dc.PODs on c.ID equals p.Consignment into pg
select new { ID = c.ID, Name = c.Name, PODs = pg };
// This is just a SAMPLE display just for kicks and grins
foreach (var r in results)
{
Console.WriteLine(r.Name + " ");
if (r.PODs.Count() > 0)
{
foreach (var pod in r.PODs)
{
Console.WriteLine("\t" + pod.Consignment + " " + pod.Description);
}
}
else
{
Console.WriteLine("\tNone");
}
}
Where the select is selecting the POD list instead of the individual match, which outputs like this:
One
1 TextBox
Two
None
Three
3 Refridgerator
3 Bucket
Four
None
Five
None