Convert SQL query to LINQ to SQL - sql

How do you convert a SQL query with nested SELECT statements to a LINQ statement?
I have the following SQL statement which outputs the results I need but I'm not sure how to replicate this in LINQ .
SELECT X.ITMGEDSC, (SUM(X.[ENDQTY_I]) - SUM(X.[ORDERLINES])) AS AVAIL
FROM SELECT T1.[MANUFACTUREORDER_I],T2.[ITMGEDSC],T1.[ENDQTY_I],
(SELECT (COUNT(VW.[MANUFACTUREORDER_I]) - 1)
FROM [PLCD].dbo.[vw_WIP_Srl] VW
WHERE VW.[MANUFACTUREORDER_I] = T1.[MANUFACTUREORDER_I]
GROUP BY VW.[MANUFACTUREORDER_I]) AS ORDERLINES
FROM [PLCD].dbo.[vw_WIP_Srl] T1
INNER JOIN [PLCD].dbo.IV00101 T2 ON T2.ITEMNMBR = T1.ITEMNMBR
GROUP BY T1 [MANUFACTUREORDER_I],T2.[ITMGEDSC],T1.[ENDQTY_I]) AS X
GROUP BY X.ITMGEDSC
ITEMNMBR is the ID of an item including a revision number, for example A1008001. The last 3 numbers denote the revision. So A1008002 are the same item, just differing revisions. In my query I need to treat these as the same item and output only the quantity for the parent item number (A1008). This parent item number is the column IV00101.ITMGEDSC.
The above code would take the following data
MANUFACTUREORDER_I ITEMNMBR ENDQTY_I
MAN00003140 A1048008 15
MAN00003507 A1048008 1
MAN00004880 A10048001 15
MAN00004880 A10048001 15
MAN00004880 A10048001 15
and output the following results
ITEMNMBR QTY
A1048008 16
A10048001 13*
The reason that this value is 13 and NOT 45 is because they are all part of the same MANUFACTUREORDER_I. In the system this therefore means that there were 15 in stock but two of these have then been transacted out of stock to be used. Hence the 3 rows, one for the goods coming into stock, the other two for two items going out of stock (ignore the quantity in these rows)
As I mentioned at the start, the SQL above gives me the output I'm after but I'm unsure how to replicate this in Linq.
UPDATE - JEFF'S ORIGINAL SOLUTION
var query = from item in db.vw_WIP_Srls
group new { item.MANUFACTUREORDER_I, item.ENDQTY_I } by item.ITEMNMBR into items
select new
{
ItemNumber = items.Key,
QtyAvailable = (from item in items
//assumes quantities equal per order number
group 1 by item into orders
select orders.Key.ENDQTY_I - (orders.Count() - 1))
.Sum()
};

Here you go. Unfortunately I couldn't see the comment you left me anymore but I believe this should be equivalent. I changed the names to match closely with your query.
var query = from a in db.vw_WIP_Srl
join b in db.IV00101 on a.ITEMNMBR equals b.ITEMNMBR
group new { a.MANUFACTUREORDER_I, a.ENDQTY_I } by b.ITMGEDSC into g
select new
{
ITMGEDSC = g.Key,
AVAIL = (from item in g
group 1 by item into orders
select orders.Key.ENDQTY_I - (orders.Count() - 1))
.Sum()
};

Related

Query for remaining balance

Query for remaining balance
I am using SQLITE 3.1.1
The scenario is the ff:
Let us say Total Quantity is 11.
The formula should be:
Total Quantity - Quantity Used = Remaining
It should look like this:
First: 11 - 1 = 10
Second: 10- 6 = 4
Third: 4 - 0 = 4
and so on..
Expected Result:
Also, Remaining value can't be lower than 0.
I currently have this SQL query but it doesn't get the Remaining query result for the next transaction but rather it always starts with Total Quantity.
SELECT
filter_maintenance.maintenance_id,
filter_maintenance.stock_id,
filter_maintenance.quantity_used,
filter_maintenance.date_registered,
filter_maintenance.date_changed,
inventories.stock_name,
SUM(inventories_order.order_quantity) - filter_maintenance.quantity_used AS Remaining
FROM filter_maintenance
INNER JOIN inventories ON filter_maintenance.stock_id = inventories.stock_id
INNER JOIN inventories_order ON filter_maintenance.stock_id = inventories_order.stock_id
GROUP BY filter_maintenance.maintenance_id
This is the output I currently have:
Your help is greatly appreciated. Thank you in advance.
Since you are using sqllite and there are no window functions you need to use a self-join instead. I assume maintenance_id is a primary key in filter_maintenance.
SELECT
filter_maintenance.maintenance_id,
filter_maintenance.stock_id,
filter_maintenance.quantity_used,
filter_maintenance.date_registered,
filter_maintenance.date_changed,
inventories.stock_name,
sum(inventories_order.order_quantity) - filter_maintenance.sum_quantity_used AS Remaining
FROM
(
SELECT fm1.*,
sum(fm2.quantity_used) AS sum_quantity_used
FROM filter_maintenance fm1
INNER JOIN filter_maintenance fm2 ON fm1.stock_id = fm2.stock_id and
fm1.date_registered >= fm2.date_registered
GROUP BY fm1.maintenance_id
) filter_maintenance
INNER JOIN inventories ON filter_maintenance.stock_id = inventories.stock_id
INNER JOIN inventories_order ON filter_maintenance.stock_id = inventories_order.stock_id
GROUP BY filter_maintenance.maintenance_id

SQL WHERE IN ... to JOIN table

SELECT
sum(CheckFinal.SUM) AS SUME,
strftime('%Y - %m', CheckDate) AS CheckDate
FROM
CheckFinal
WHERE CheckFinal.NUMER IN (
SELECT
CheckDetail.NUMER
FROM
CheckDetail
WHERE
CheckDetail.NUMER IN (
SELECT
PriceList.UniqID AS PriceListUniqID,
PriceList.Name AS PriceListName,
Category.UniqID
FROM
PriceList Join Category on PriceList.CATEGORY = Category.UniqID
WHERE (Category.UniqID = 2)
)
)
GROUP BY strftime('%Y %m', CheckDate);
I have such query to combine data out of 4 tables:
— Category (100 records)
— PriceList (20'000 records)
— CheckDetail (10'000'000 records)
— CheckFinal (2'000'000 records)
In plain word, I'm looking for PriceList items, that are marked as children of Category.UniqID #2, then I would like to collect all CheckDetail.NUMER inset to define all sales value with such PriceList items. Futhermore, I'm looking for possobility to collect all CheckFinal.NUMERs.
The problem I have is:
It's not possible to make SELECT procedure three (3) time nested (SQLite.3), I think it's time to make JOINs but I have no experience in joining
CheckDetail is a HUGE data set, it's take 2 seconds to find just one PriceList item across 10 million records and I have 3'000 items in my query WHERE (Category.UniqID = 2)
In my case, I should lookup 3'000 times through 5'000'000 records, but I have 10 sets and the query will spend about 10 hours to complit.
Is JOIN will optimize query time? How to make such JOIN QUERY?
Is there any GUI tools to make query with constructor or something like that?
UPD:
http://sqlfiddle.com/#!5/50a93/2 (use SQL.js for inserting several rows of data)
WITH JOIN , you query would look like
SELECT
sum(CF.SUM) AS SUME,
strftime('%Y - %m', CF.CheckDate) AS CheckDate
FROM
PriceList
Join Category
on PriceList.CATEGORY = Category.UniqID
AND Category.UniqID = 2
JOIN CheckDetail CD
ON CD.NUMBER = PriceList.UniqID
JOIN CheckFinal CF
ON CF.NUMBER = CD.NUMBER
GROUP BY strftime('%Y - %m', CF.CheckDate);

Update 1 field in a table from another field in a different table (OS400, not a 1 to 1 relationship)

Im trying to update a field in a table from another field in a different table.
The table being updated will have multiple records that need updating from 1 match in the other table.
Example, i have a 1 million row sales history file. Those million records have aproximately 40,000 different sku codes, each row has a date and time stamp. Each sku will have multiple records in there.
I added a new field called MATCOST (material cost).
I have a second table containing SKU and the MATCOST.
So i want to stamp every line in table 1 with the corresponding SKU's MATCOST in table2. I cannot seem to achieve this when its not a 1 to 1 relationship.
This is what i have tried:
update
aulsprx3/cogtest2
set
matcost = (select Matcost from queryfiles/coskitscog where
aulsprx3/cogtest2.item99 = queryfiles/coskitscog.ITEM )
where
aulsprx3/cogtest2.item99=queryfiles/coskitscog.ITEM
But that results in the SQL error: Column qualifier or table COSKITSCOG undefined and highlighting the q in the last reference to queryfiles/coskitscog.Item
Any idea's ?
Kindest Regards
Adam
Update: This is what my tables look like in principle. 1 Table contains the sales data, the other contains the MATCOSTS for the items that were sold. I need to update the Sales Data table (COGTEST2) with the data from the COSKITCOG table. I cannot use a coalesce statement because its not a 1 to 1 relationship, most select functions i use result in the error of multiple selects. The only matching field is Item=Item99
I cant find a way of matching multiple's. In the example we would have to use 3 SQL statements and just specify the item code. But in live i have about 40,000 item codes and over a million sales data records to update. If SQL wont do it, i suppose i'd have to try write it in an RPG program but thats way beyond me for the moment.
Thanks for any help you can provide.
Ok this is the final SQL statement that worked. (there were actually 3 values to update)
UPDATE atst2f2/SAP20 ct
SET VAL520 = (SELECT cs.MATCOST
FROM queryfiles/coskitscog cs
WHERE cs.ITEM = ct.pnum20),
VAL620 = (SELECT cs.LABCOST
FROM queryfiles/coskitscog cs
WHERE cs.ITEM = ct.pnum20),
VAL720 = (SELECT cs.OVRCOST
FROM queryfiles/coskitscog cs
WHERE cs.ITEM = ct.pnum20),
WHERE ct.pnum20 IN (SELECT cs.ITEM
FROM queryfiles/coskitscog cs)
This more compact way to do the same thing should be more efficient, eh?
UPDATE atst2f2/SAP20 ct
SET (VAL520, VAL620, VAL720) =
(SELECT cs.MATCOST, cs.LABCOST, cs.OVRCOST
FROM queryfiles/coskitscog cs
WHERE cs.ITEM = ct.pnum20)
WHERE ct.pnum20 IN (SELECT cs.ITEM
FROM queryfiles/coskitscog cs)
Qualify the columns with correlation names.
UPDATE AULSPRX3/COGTEST2 A
SET A.matcost = (SELECT matcost
FROM QUERYFILES/COSKITSCOG B
WHERE A.item99 = B.item)
WHERE EXISTS(SELECT *
FROM QUERYFILES/COSKITSCOG C
WHERE A.item99 = C.item)
From UPDATE, I'd suggest:
update
aulsprx3/cogtest2
set
(matcost) = (select Matcost from queryfiles/coskitscog where
aulsprx3/cogtest2.item99 = queryfiles/coskitscog.ITEM)
where
aulsprx3/cogtest2.item99=queryfiles/coskitscog.ITEM
Note the braces around matcost.

How to join every row from one table, with the latest dated row from another table, using LINQ2SQL

Let's say I've got a table called [Items] which has a primary key ItemID, and I've got a table called [ItemStatuses] which is linked with the ItemID, has a Auto-Increment ID and has a Date (and other columns to capture various things)
Which means, for every Item, I'll have many ItemStatuses.
Items:
ItemID
1
2
ItemStatuses:
ID ItemID Date
----------------------------
1 1 1/1/2010...
2 1 1/2/2010...
3 1 1/3/2010...
4 2 1/1/2010...
5 2 1/2/2010...
I want to be able to join each Item with the latest ItemStatus. I've got a solution which grabs the information into entity objects and then does the work, but this takes so much time. If I could query this using LINQ2SQL it would be so much faster. I've read several other questions on stackoverflow but none of the examples make sense for my scenario. I've tried to figure this out, but still cannot get it to work.
I need this:
ItemID Date
-----------------------
1 1/3/2010...
2 1/2/2010...
This is a simplistic example. I don't want just specific columns. There are MANY columns in the Items and ItemStatuses that I need to capture. But the ones mentioned are the control columns.
If someone could give me a hand I would really appreciate it.
The query I have now doesn't work, but it's where I'm at right now:
var results = from i in context.Items
from s in context.ItemStatuses
where s.ItemID.Equals(i.ItemID) s.Date <= inputDate
orderby s.Date descending
select new { i, s };
The Following query joins the two tables and selects only the ItemStatuses that has the latest Date value:
var results = from i in context.Items
join s in context.ItemStatuses
on
new
{
ID = i.ItemID,
maxDate = (
from ss in context.ItemStatuses
where ss.Date <= inputDate
select ss.Date
).max
}
equals new
{
ID = s.ItemID,
maxDate = s.Date
}
select new
{
i.ItemID, s.Date
};

LINQ query help please. Selecting most recent record for each FK

Let's say I have a table that looks like this:
Id CheckboxId Selected DateCreated
1 1 1 1/1/2010
2 2 1 1/2/2010
3 1 0 1/3/2010
4 3 1 1/4/2010
5 3 0 1/5/2010
CheckboxId is a FK and the table is just a history of when the boxes are checked or unchecked.
What I want to get is the most recent record for each CheckboxId. In the case of my demo table I want rows 2, 3, and 5. How would you accomplish this? Also I'm sure this is as easy as a "where" at the beginning of the query but if it could also be modified to only get records before a specified date that would be fantastic.
I'm having trouble figuring out how I would write a query to do this in SQL and it's making a link query impossible. I'm sure it has to be a selection from a sub query of distinct checkboxIds coupled with a group by or something but my SQL just isn't that great.
Many thanks for your help.
Should be something like this:
var results = (from x in context
group x by x.CheckboxID into g
select new
{
CheckboxID = g.Key,
MaxItem = g.OrderByDescending(o => o.DateCreated).FirstOrDefault()
});
Then you can do:
foreach (var x in results)
x.MaxItem.Selected //...etc.
Use a subquery to get the most recent entries per CheckBoxId, then join to that table to get the rest of the results:
;with CheckBoxRecent as (
select
CheckBoxId
,max(DateCreated) as MostRecentDate
from
CheckBoxData T
where
T.DateCreated < #SpecifiedDate
group by
CheckBoxId
)
select
T1.*
from
CheckBoxData T1
inner join
CheckBoxRecent T2 on T1.CheckBoxId = T2.CheckBoxId
and T1.DateCreated = T2.MostRecentDate
order by
CheckBoxId
I leave it as an exercise for the reader to convert to LINQ :)
According to your comment you want checkboxes selected on a specified date
var results = db.CheckBoxHistory.Where(cbh => cbh.Selected == 1 && cbh.DateCreated.Date == DateSpecified)
will get you those results, if you want to limit it to the latest by CheckboxId just add this
.GroupBy(cbh => cbh.CheckboxId)
you could loop the results and grab the latest for each checkboxid like so
foreach(var result in results) {
var latest = result.OrderByDescending(cbh => cbh.DateCreated).FirstOrDefault();
//latest has all fields in the checkboxhistory table
}