Subtracting 2 columns from different tables with the same ID - c#

I have 2 tables TblAddToInventory and TblWithdrawnFromInventory. Both have ProductID and Quantity. When a withdrawal is made, naturally the Inventory should deduct the quantity of items but only items that have been withdrawn. Example:
TblAddToInventory
ProductID | Quantity | Amount | Date
1 2 2.00 7/7/2012
2 3 3.00 7/7/2012
3 4 4.00 7/7/2012
2 2 2.00 7/8/2012
3 3 3.00 7/8/2012
TblWithdrawnFromInventory
ProductID | Quantity | Amount | Date
2 4 4.00 7/9/2012
3 5 5.00 7/10/2012
With this, when I join the two tables and deduct the specific columns, I should have a DataGridView using C# with this data:
ProductID | Quantity | Amount
1 2 2.00
2 1 1.00
3 2 2.00
I know how to use SUM and JOIN but I just don't know how to create a syntax that will subtract two columns from different tables with the same ID.
I don't know if this is the right way but what I have in mind is SUM all from TblAddToInventory using GROUP BY then SUM all from TblWithdrawnFromInventory using GROUP BY and then SUBTRACT columns from TblAddToInventory and TblWithdrawnFromInventory using GROUP BY. But I don't think that's a good idea. Can you help?
Thank you.

I know how to use SUM and JOIN but I just don't know how to create a
syntax that will subtract two columns from different tables with the
same ID.
This is code how you to do this:
SELECT inventory.ProductId,
inventory.Quantity - ISNULL(withdrawal.Quantity,0) AS Quantity,
inventory.Amount - ISNULL(withdrawal.Amount,0) AS Amount
FROM (
SELECT ProductId, SUM(Quantity) AS Quantity, SUM(Amount) AS Amount
FROM TblAddToInventory
GROUP BY ProductId
) AS inventory
LEFT JOIN (
SELECT ProductId, SUM(Quantity) AS Quantity, SUM(Amount) AS Amount
FROM TblWithdrawnFromInventory
GROUP BY ProductId
) AS withdrawal ON inventory.ProductId = withdrawal.ProductId

Preparation:
-- create temp table with the data, cast the first row's date to set the proper data type
select * into #tblAddToInventory from (
select 1 as ProductID, 2 as Quantity, 2.00 as Amount, cast('7/7/2012' as date) as [Date]
union all select 2 as ProductID, 3 as Quantity, 3.00 as Amount, '7/7/2012' as Date
union all select 3 as ProductID, 4 as Quantity, 4.00 as Amount, '7/7/2012' as Date
union all select 2 as ProductID, 2 as Quantity, 2.00 as Amount, '7/8/2012' as Date
union all select 3 as ProductID, 3 as Quantity, 3.00 as Amount, '7/8/2012' as Date
) a
-- create temp table with the data, cast the first row's date to set the proper data type
select * into #tblWithdrawnFromInventory from (
select 2 as ProductID, 4 as Quantity, 4.00 as Amount, cast('7/9/2012' as date) as [Date]
union all select 3 as ProductID, 5 as Quantity, 5.00 as Amount, '7/10/2012' as Date
) b
-- verify the data looks correct
select * from #tblAddToInventory
-- ProductID Quantity Amount Date
-- ----------- ----------- ----------- ----------
-- 1 2 2.00 2012-07-07
-- 2 3 3.00 2012-07-07
-- 3 4 4.00 2012-07-07
-- 2 2 2.00 2012-07-08
-- 3 3 3.00 2012-07-08
-- verify the data looks correct
select * from #tblWithdrawnFromInventory
-- ProductID Quantity Amount Date
-- ----------- ----------- ----------- ----------
-- 2 4 4.00 2012-07-09
-- 3 5 5.00 2012-07-10
Begin solution:
-- use Union All to join the queries, and multiply the second query by -1 to make them negative
select * from #tblAddToInventory union all
select ProductID, (Quantity * -1) as Quantity, Amount, Date from #tblWithdrawnFromInventory
-- ProductID Quantity Amount Date
-- ----------- ----------- ----------- ----------
-- 1 2 2.00 2012-07-07
-- 2 3 3.00 2012-07-07
-- 3 4 4.00 2012-07-07
-- 2 2 2.00 2012-07-08
-- 3 3 3.00 2012-07-08
-- 2 -4 4.00 2012-07-09
-- 3 -5 5.00 2012-07-10
select ProductID, sum(Quantity) as Quantity, sum(Amount) as Amount from (
select * from #tblAddToInventory union all
select ProductID, (Quantity * -1) as Quantity, (Amount * -1) as Amount, Date from #tblWithdrawnFromInventory
) joinedData
where [Date] >= '7/6/2012' and [Date] <= '7/11/2012'
group by ProductID
-- ProductID Quantity Amount
-- ----------- ----------- -----------
-- 1 2 2.00
-- 2 1 1.00
-- 3 2 2.00
-- delete temp tables
drop table #tblAddToInventory
drop table #tblWithdrawnFromInventory

Related

Remove need for second T-SQL query

I am loading some data into a repeater which is coming from two tables. The query against the second table is only selecting the MAX record though, and because of this complexity, I'm having to create a child repeater to then go off and find the Max record to display.
Table A: Activity List
ID | Activity
----+-----------------------
1 | Change Oil Filter
2 | Change brake fluid
3 | Change brake rotors
Table B: Mechanics Log
ID | ActivityID | Date | Mechanic | Comment
---+-------------+-------------+-------------------------------------------
1 | 1 | 2019-27-06 | John | Changed the oil filter
2 | 1 | 2019-26-06 | Sally | No oil filters in stock.
3 | 2 | 2019-20-06 | Sally | Brake fluid flushed.
As stated above, I can produce the following table using two repeaters (one inside the other) and it looks like this.
ActivityID | Date | Mechanic | Comment
-------------+-------------+-----------------------------------------
1 | 2019-27-06 | John | Changed the oil filter
2 | 2019-20-06 | Sally | Brake fluid flushed.
3 | | |
My question is: How can I produce the same table but using only one repeater and 1 T-SQL query? Is it possible? The reason being is that this is a very simple list (shortened for this demonstration) of the full list I have to enable for my mechanics work log, and when i start going to 100+ activities that can be done on a vehicle, the page loads quite slow; assuming because it has to fire off the 2nd repeater + code for each record it has bound.
I also apologize I do not yet have a 'starting point' for you to work with, as nothing I have created has come even close to producing the result in one query. I am having trouble working out how I combine the first part of the query with the MAX(Date) of the 2nd table. Hoping for some assistance from the community to help.
You can use the below query to get the desired result -
Sample Data
Declare #ActivityList Table
(ID int, Activity varchar(100))
Insert into #ActivityList
values
(1 , 'Change Oil Filter' ),
(2 , 'Change brake fluid' ),
(3 , 'Change brake rotors' )
Declare #MechanicsLog Table
(ID int, ActivityID int, [Date] Date, Mechanic varchar(20), Comment varchar(50))
Insert into #MechanicsLog
values
(1 , 1 , '2019-06-27' , 'John' , 'Changed the oil filter' ),
(2 , 1 , '2019-06-26' , 'Sally' , 'No oil filters in stock.' ),
(3 , 2 , '2019-06-20' , 'Sally' , 'Brake fluid flushed.' )
Query
;With cte as
(select ActivityID, Max([Date]) [date] from #MechanicsLog ml
Group By ActivityID
)
Select al.ID, al.Activity, cte.[Date], Mechanic, Comment
from cte inner join #MechanicsLog ml
on cte.ActivityID = ml.ActivityID and cte.[date] = ml.[Date]
right join #ActivityList al on al.ID = ml.ActivityID
order by ID
If you add use the ROW_NUMBER function to add a sequence to each activity ID, you can then filter that to only get the most recent for each activity ID.
select ActivityID, Date, Mechanic, Comment
from
(
select *, ROW_NUMBER() OVER (PARTITION BY ActivityID order by Date desc) RowNumber
from MechanicsLog
) q1
where RowNumber = 1
This gives you the "MAX" record for each ActivityID but with the rest of the record, so you can join to the Activity List table if you want.
select
act.ActivityID, Max(log.[Date]) as [Date]
from
ActivityList act
inner join
MachineLog log on log.ActivityID = act.ActivityID
Group by
act.ActivityID

Inventory Stock report Using 3 Sql Tabel Out Put in Crystal Report

I have 4 tables: Purchase, Purchase Return, Sale, Sale Return.
All tables include the same columns.
In Purchase Table transaction:
Id Date ItemCode Qty Purchase Rate
1 |01-01-17 00001 20 500
In sale Table table transaction:
Id Date ItemCode Qty sale Rate
1 01-01-17 00001 10 500
I want to display date-wise report in Crystal Report like this:
Opening Stock ItemCode Purchase Purchase Return Sale SaleReturn Balance
0 00001 20 0 10 0 10
10 00001 0 0 0 0 10
I tried this query:
ALTER PROCEDURE [dbo].[SpStockQtyDate1]
as
Begin
with i as
(select SIZE, sum(qty) as QtyIn from PurchaseTable where date >='2017-02-14' and date <='2017-02-14' group by Size),
o as
(
select size, sum (qty) as QtyOut from InvoiceTable where date >='2017-02-14' and date <='2017-02-14' group by Size)
select COALESCE (i.Size,o.Size) as size,COALESCE (QtyIn,0) as stock_in,
COALESCE (QtyOut,0) as stock_Out,
COALESCE (QtyIn,0)-COALESCE(QtyOut,0) as Stock_Balance
from i
full join
o
on o.size=i.Size
End

Monthly Report - SQL

I have the table below, how would I select in SQL the last date of each month (from the list) in each categoryID?
I want to end up with something in the line off:
CategoryID | Current | Date
1 | 5 | 2016-09-30
1 | 3 | 2016-10-30
1 | 7 | 2016-11-30
1 | 2 | 2016-12-30
etc. as history builds up.
Image :
There are a few ways to approaches to do this, one of them could be using windowing function rownumber. Within the CTE (WITH) you get local order of the records within date(using covert to get rid of the time here)+CategoryID partition by datetime DESC (-> first is latest). You need to do this because you cannot use windowing functions in WHERE clause. Then, in the main query, you actually use this CTE as your source table and get only the latest record per partition.
WITH LocallyOrdered AS (
SELECT CategoryID,
StockCurrent,
ROW_NUMBER() OVER (
PARTITION BY CategoryID, CONVERT(date, RecordAdded)
ORDER BY RecordAdded DESC)
AS RowNumberOneIsLatest
FROM OriginalTable)
SELECT CategoryID, StockCurrent FROM LocallyOrdered WHERE RowNumberOneIsLatest = 1
Considering you're using MySQL, since you haven't mentioned.
Suppose this is your table named : 'Dummy'
cat_id current date
------ ------- --------
1 5 2016-09-30
1 3 2016-10-30
1 7 2016-11-30
1 2 2016-12-30
2 4 2016-10-31
2 6 2016-10-04
Executing this query :
select
o.cat_id,
(SELECT DISTINCT
a.date
from
Dummy a
where a.cat_id = o.cat_id
ORDER BY date DESC
LIMIT 1) as 'date'
from
Dummy o
group by o.cat_id ;
Gives you the Latest date of each category :
cat_id date
------ ------------
1 2016-12-30
2 2016-10-31
EDIT
This is supposed to work specifically for your table. Just replace "yourTable" with the table's actual name.
select
o.CategoryID,
o.StockCurrent
(SELECT DISTINCT
a.RecordAdded
from
yourTable a
where a.CategoryID = o.CategoryID
ORDER BY RecordAdded DESC
LIMIT 1) as 'RecordAdded'
from
yourTable o
group by o.CategoryID ;
EDIT 2 :
This Query returns the latest date of each month within a certain category. Hope this is what you want.
SELECT
o.CategoryID,
o.StockCurrent,
o.RecordAdded
FROM
`yourTable` o
WHERE o.RecordAdded IN
(SELECT
MAX(i.RecordAdded)
FROM
`yourTable` i
GROUP BY MONTH(i.RecordAdded))
GROUP BY o.CategoryID,
o.RecordAdded ;
Suppose the table contains the following sample data:
CategoryID StockCurrent RecordAdded
---------- ------------ -------------
1 5 2016-09-01
1 3 2016-09-02
1 7 2016-10-01
1 2 2016-10-02
2 4 2016-09-01
2 6 2016-09-02
2 66 2016-10-01
2 77 2016-10-02
Running this query returns the following result set :
CategoryID StockCurrent RecordAdded
---------- ------------ -------------
1 3 2016-09-02
1 2 2016-10-02
2 6 2016-09-02
2 77 2016-10-02
try this:
WITH Temp As
(
select CategoryId, [Current], RecordAdded,
Dense_Rank() over( partition by CategoryId order by RecordAdded desc) as CatergoryWiseRank
from tblCategory
)
select CategoryId, [Current], RecordAdded from Temp where CatergoryWiseRank=1
SELECT
CASE MONTH(date_field)
WHEN 1 THEN 'Enero'
WHEN 2 THEN 'Febrero'
WHEN 3 THEN 'Marzo'
WHEN 4 THEN 'Abril'
WHEN 5 THEN 'Mayo'
WHEN 6 THEN 'Junio'
WHEN 7 THEN 'Julio'
WHEN 8 THEN 'Agosto'
WHEN 9 THEN 'Septiembre'
WHEN 10 THEN 'Octubre'
WHEN 11 THEN 'Noviembre'
WHEN 12 THEN 'Diciembre'
END as Mes, COUNT(date_field) as cantidad FROM nacimientos
WHERE YEAR(date_field)='1991'
GROUP BY MONTH(date_field)asc
Result

MySQL SELECT UNION Distinct on single column

I have two tables for storing exchange rates in my system. the first one
agent_rate is as follows.
ID Currency Rate
=======================
3 GBP 0.65
4 EUR 0.70
5 JPY 57.4
the second table exchange_rate is as follows.
ID Currency Rate
=======================
1 USD 1
2 ZMK 200
3 GBP 0.5
4 EUR 0.75
5 JPY 60.4
6 CHF 0.9
I want to select all the rows in the first table agent_rate and then add all the missing values of ID from the exchange_rate table. I wanted to use a union statement with distinct on a single column but I failed to. My current solution as follows (visual studio)
select from agent_rate table and fill rate datatable
set unique field i.e. ID in rate datatable
select and fill from exchange_rate table into a temp datatable
move records from temp datatable to rate datatable and ignore errors
the resulting table is(should be) as follows:
ID Currency Rate
=======================
1 USD 1
2 ZMK 200
3 GBP 0.65
4 EUR 0.70
5 JPY 57.4
6 CHF 0.9
Is there a better way to do this in Sql?
You can join the table and select the agent values first if they exist, otherwise the vaolue from the exchange table
select coalesce(a.id, e.id) as id,
coalesce(a.currency, e.currency) as currency,
coalesce(a.rate, e.rate) as rate
from exchange_rate e
left agent_rate a on a.id = e.id
coalesce returns the first non-null value in the list provided.

select max value from oracle table in c#

I have an OracleCommand to select maximum value of type NUMBER from oracle table in a C# application using OracleConnection. when code is excuted I get the value with M letter at the end! so if we suppose max value is 2544, then I get 2544M as maximum value.
here is the code:
OracleCommand command = new OracleCommand("SELECT GREATEST(TA_Counts) FROM Test3.Trn_Sfd", Con2);
Con2.Open();
var returvalue = command.ExecuteScalar();
why value is not return as 2544 int value?!
Because the value is a decimal. This happens due to the type of your column in table. You could verify this looking at this table. If your data type is either integer or float the .net type returned by the reader is decimal.
Greatest doesn't give you the max value of your table:
SQL> with t as (
2 select 1 id, 2 value from dual union all
3 select 2 id, 4 value from dual
4 )
5 select GREATEST(id)
6 from t
7 /
GREATEST(ID)
------------
1
2
The GREATEST function gives you the max value among several values, like:
SQL> ed
Wrote file afiedt.buf
1 with t as (
2 select 1 id, 2 value from dual union all
3 select 2 id, 4 value from dual
4 )
5 select GREATEST(id, value)
6* from t
SQL> /
GREATEST(ID,VALUE)
------------------
2
4
You have to use the max function:
SQL> ED
Wrote file afiedt.buf
1 with t as (
2 select 1 id, 2 value from dual union all
3 select 2 id, 4 value from dual
4 )
5 select max(id)
6* from t
SQL> /
MAX(ID)
----------
2
you might need to use implicit conversion:
(int)command.ExecuteScalar()
use the type you need

Categories