Im trying to use GORM to select only items from the parent table that have a matching condition in a related table.
type Table1 struct {
gorm.Model
Name string
Email string
Items Table2
}
type Table2 struct {
gorm.Model
Product string
otherfield string
}
I want to return all Table1 items that have Product in Table2 set to a specific value. So far I am getting mssql: The multi-part identifier "visits.sign_out_time" could not be bound. a lot.
My command is
var items []Table2
db.Debug().Preload("Table2").Where("table2.product = ?", "xxx").Find(&items).GetErrors()
Not entirely sure where I'm going wrong but for whatever reason the .Where() cannot access the second, preloaded table. How do I go about using GORM to achieve what I am trying to do?
Thanks,
Alex
The Where("table2.product = ?", "xxx") cannot access the second (preloaded) table because Preload is not a JOINS, it's a separate SELECT query. Your code creates two separate queries, something like this:
// first query
SELECT * FROM table1 WHERE table2.product = 'xxx';
// second query
SELECT * FROM table2;
In order to return all Table1 records that have Product in Table2 set to a specific value you have to do the following:
var t1 []Table1
err = db.
Where(`EXISTS(SELECT 1 FROM table2 t2 WHERE t2.product = ? AND table1.id = t2.table1_id)`, productValue).
Find(&t1).Error
Note that AND table1.id = t2.table1_id part is just an example how the two tables might be related, you may have a different relation and you'll need to modify the query accordingly.
If you want GORM to populate the t1.Items with the Table2 data, you prepend Preload("Items") to the above query.
If you only want only Items, you can directly query on Table2 no need to preload Table1
var items []Table2
db.Where("product = ?", "xxx").Find(&items).GetErrors()
Or you need all data of Table1 then Join with table2 then use where clause
db.Debug().Joins("JOIN table2 ON table1.id = table2.table1_id")
.Where("table2.product = ?", "xxxx").Find(&table1data)
Here I don't see any foreign key in Table2 for join.You can add one.
type Table2 struct {
gorm.Model
Product string
Table1ID uint
}
Related
Let me explain the question.
I have two tables, which have 3 columns with same data tpyes. The 3 columns create a key/ID if you like, but the name of the columns are different in the tables.
Now I am creating queries with these 3 columns for both tables. I've managed to independently get these results
For example:
SELECT ID, FirstColumn, sum(SecondColumn)
FROM (SELECT ABC||DEF||GHI AS ID, FirstTable.*
FROM FirstTable
WHERE ThirdColumn = *1st condition*)
GROUP BY ID, FirstColumn
;
SELECT ID, SomeColumn, sum(AnotherColumn)
FROM (SELECT JKM||OPQ||RST AS ID, SecondTable.*
FROM SecondTable
WHERE AlsoSomeColumn = *2nd condition*)
GROUP BY ID, SomeColumn
;
So I make a very similar queries for two different tables. I know the results have a certain number of same rows with the ID attribute, the one I've just created in the queries. I need to check which rows in the result are not in the other query's result and vice versa.
Do I have to make temporary tables or views from the queries? Maybe join the two tables in a specific way and only run one query on them?
As a beginner I don't have any experience how to use results as an input for the next query. I'm interested what is the cleanest, most elegant way to do this.
No, you most probably don't need any "temporary" tables. WITH factoring clause would help.
Here's an example:
with
first_query as
(select id, first_column, ...
from (select ABC||DEF||GHI as id, ...)
),
second_query as
(select id, some_column, ...
from (select JKM||OPQ||RST as id, ...)
)
select id from first_query
minus
select id from second_query;
For another result you'd just switch the tables, e.g.
with ... <the same as above>
select id from second_query
minus
select id from first_query
I have a table something like this:
ID|Value
01|1
02|4
03|12
01|5
02|14
03|22
01|9
02|32
02|62
01|13
03|92
I want to know how much progress have each id made (from initial or minimal value)
so in sybase I can type:
select ID, (value-min(value)) from table group by id;
ID|Value
01|0
01|4
01|8
01|12
02|0
02|10
02|28
02|58
03|0
03|10
03|80
But monetdb does not support this (I am not sure may be cz it uses SQL'99).
Group by only gives one column or may be average of other values but not the desired result.
Are there any alternative to group by in monetdb?
You can achieve this with a self join. The idea is that you build a subselect that gives you the minimum value for each id, and then join that to the original table by id.
SELECT a.id, a.value-b.min_value
FROM "table" a INNER JOIN
(SELECT id, MIN(value) AS min_value FROM "table" GROUP BY id) AS b
ON a.id = b.id;
I need the fields in 1 table contingent on 1 property matching rows in another table.
I can write this query in SQL with a subquery as such:
SELECT *
FROM Table1
WHERE Property1 IN
(
SELECT Property1
FROM Table2
WHERE Property0 = 1
)
But I read here that it's less complicated and just as easy to write with a join, which I did. However, so far I'm unable to return just Table1 as I'd like since I'm using a join, which if I'm not mistaken, requires me to create this anonymous type, as below. What I did here works (I created another object with the same properties of Table1 I need), but I can't help thinking there's a better way to do this.
Table1.Join(Table2, t1 => t1.Property1, t2 => t2.Property1, (t1, t2) => new
{
t1.Property1,
t1.Property2,
t1.Property3
})
.Select(ob => new UnnecessaryObject
{
Property1 = ob.Property1,
Property2 = ob.Property2,
Property3 = ob.Property3
}
I also tried just creating a Table1 in the .Select part, but I got an error about explicit construction not being allowed.
Just to clarify, I'd like to be able to return the IQueryable of type Table1, which it seems like I ought to be able to do without having to create UnnecessaryObject...but I'm still pretty new to LINQ, so I'd appreciate any help you can offer. Thanks in advance.
You could just do:
from t1 in table1
join t2 in table2 on t1.property1 equals t2.property1
select t1;
That would return a collection of table1 objects. This assumes from your example table1 is a collection of table1 objects and table2 is a collection of table2 objects.
The best translation of your original query I can come up with is:
from item in context.Table1
where context.Table2
.Where(x => x.Property0 == 0)
.Any(x => x.Property1 == item.Property1)
select item
This selects all items from Table1, where there's an item with matching Property1 and Property0 == 0 from Table2
It can also be solved with a join indeed. To get an efficient join, you need to have a relation between the two tables. Then you can do something like assuming the relation is called RelatedItems:
from item in context.Table1
join relatedItem in item.RelatedItems
on item.Property1 equals relatedItem.Property
where relatedItem.Property0 == 0
select item
This is equivalent to the SQL:
SELECT *
FROM Table1
JOIN Table2 ON Table1.Property1 = Table2.Property1
WHERE Table2.Property0 = 0
I need to move some code from C# into a Stored Procedure for speed reasons. What I'm trying to get is a unique list of TemplateIds from the RoleTemplates (or CategoryToRoleTemplate) table based on a CategoryId.
However, I need the query to walk the Category.ParentId relationship, and collection all of the parent's related TemplateIds. This needs to happen until the ParentId is null.
Ideally the result should be a unique list of RoleTemplate.TemplateIds.
Table structure...
Categories
------------------------------
CategoryId uniqueidentifier
ParentId uniqueidentifier <-- Relationship to Categories.CategoryId.
Name varchar (50)
CategoryToRoleTemplate
------------------------------
CategoryId uniqueidentifier <-- Relationship to Categories.CategoryId.
TemplateId uniqueidentifier <-- Relationship to RoleTemplates.TemplateId.
RoleTemplates
------------------------------
TemplateId uniqueidentifier
Name varchar (50)
I'm using SQL Server 2008 R2.
Thanks!
EDIT:
Final solution:
with CategoryHierarchy (ParentId)
as (
-- Anchor member definition
select CategoryId from Categories
where CategoryId = #id
union all
-- Recursive member definition
(select c.ParentId from Categories as c
inner join CategoryHierarchy as p
on c.CategoryId = p.ParentId)
)
select distinct TemplateId from CategoryToRoleTemplates where CategoryId in (select CategoryId from CategoryHierarchy);
Thanks to all who answered! CTEs were the key.
I would suggest a CTE for doing that query. Keep in mind though that the tree will actually START at null and go until exhausted.
Example (may or may not work OOB given your code):
; WITH CategoryTree(CategoryID, sorthelp) AS
(SELECT CategoryID, 0 FROM Categories WHERE ParentID IS NULL)
UNION ALL
(SELECT C.CategoryID, CT.sorthelp + 1 FROM Categories C INNER JOIN CategoryTree CT ON C.PARENTID = CT.CategoryID)
SELECT DISTINCT TemplateID FROM RoleTemplates WHERE CategoryID IN (SELECT CategoryID FROM CategoryTree)
Good Point(tm): Don't forget the semicolon before the WITH keyword.
Use a recursive common table expression:
http://msdn.microsoft.com/en-us/library/ms186243.aspx
Please check this link http://msdn.microsoft.com/en-us/library/ms186243.aspx
I would go first with the table Categories with the with syntax and after that join with the others tables.
I'm short on time at the moment, so I can't be specific, but I would look into Common Table Expressions, which I've used successfully in the past to implement recursion.
I would like to return all rows from TableA table that does not exists in another table.
e.g.
select bench_id from TableA where bench_id not in (select bench_id from TableB )
can you please help me write equivalent LINQ query. Here TableA is from Excel and TableB is from a Database
I am loading Excel sheet data into DataTable, TableA. TableB I am loading from Database. In short, TableA and TableB is type of DataTable
So if table A is from Excel, are you loading the data into memory first? If so (i.e. you're using LINQ to Objects) then I suggest you load the IDs in table B into a set and then use:
var query = tableA.Where(entry => !tableBIdSet.Contains(entry.Id));
If this isn't appropriate, please give more details.
Converting into a set is probably best done just by using the HashSet constructor which takes an IEnumerable<T>. For example:
var tableBIdSet = new HashSet<string>(db.TableB.Select(entry => entry.Id));
(If the IDs aren't actually distinct, you could add a call to Distinct() at the end.)
var lPenaltyEmployee = from row1 in tBal.getPenaltyEmployeeList().AsEnumerable()
select row1;
var PenaltyEmp = new HashSet<string>(lPenaltyEmployee.Select(Entry => Entry.Emsrno);
DataTable lAbsentEmp = (from row in tBal.getAbsentEmployee(txtFromDate.Text).AsEnumerable()
where !(PenaltyEmp).Contains(row["Emsrno"].ToString())
select row).CopyToDataTable();
From a in TableA
Group Join b in TableB on a.bench_id Equalsb.bench_id into g = Group
Where g.Count = 0
Select a