How to subtract the old value with current value from database? - sql

my question is I have 2 tables. let say Table Old and Table Current. Both tables have columns Quantity. Old.Quantity is the old values, and Current.Quantity is the current values.
Table Old :
id pro.no Quantity
1 123 3
Table Current :
id pro.no Quantity
1 123 2
SQL :
SELECT A.`Quantity`, B.`Quantity`
FROM Table Current A
LEFT JOIN Table Old B ON B.`pro.no` = A.`pro.no`
WHERE A.`id` = '1'
So, I want to subtract both values to get the new values which is 1 So that, when user key in the pro.no into the textbox, it'll show them they new value for Quantity is 1.
I am using VB.NET for the backend, and I'm still new for this language too.

You can simply subtract both columns, however as this is a left join you'll need to care for the null values:
SELECT CASE
WHEN o.quantity IS NULL THEN c.quantity
ELSE c.quantity - o.quantity
END
FROM current c LEFT JOIN old o ON ... WHERE ...
or alternatively
SELECT c.quantity - CASE WHEN o.quantity IS NULL THEN 0 ELSE o.quantity END
FROM current c LEFT JOIN old o ON ... WHERE ...

Related

JOIN query, SQL Server is dropping some rows of my first table

I have two tables customer_details and address_details. I want to display customer details with their corresponding address, so I was using a LEFT JOIN, but when I'm executing this query, SQL Server drops rows where street_no of customer_details table doesn't match with the street_no in address_detials table and displays only rows where `street_no' of customer_detials = street_no of address_details table. I need to display a complete customer_details table and in case if street_no doesn't matches it should display empty string or anything. Am I doing anything wrong in my SQL join?
Table customer_details:
case_id customer_name mob_no street_no
-------------------------------------------------
1 John 242342343 4324234234234
1 Rohan 343233333 43332
1 Ankit 234234233 2342332423433
1 Suresh 234234324 2342342342342
1 Ranjeet 343424323 32233
1 Ramu 234234333 2342342342343
Table address_details:
s_no streen_no address city case_id
------------------------------------------------------
1 4324234234234 Roni road Delhi 1
2 2342332423433 Natan street Lucknow 1
3 2342342342342 Koliko road Herdoi 1
SQL JOIN query:
select
a.*, b.address
from
customer_details a
left join
address_details b on a.street_no = b.street_no
where
b.case_id = 1
Now that it became clear that you used b.case_id=1, I will explain why it filters:
The LEFT JOIN itself returns some rows that contain all NULL values for table b in the result set, which is what you want and expect.
But by using WHERE b.case_id=1, the rows containing NULL values for table b are filtered out because none of them matches the condition (all those rows have b.case_id=NULL so they don't match).
It might work to instead use WHERE a.case_id=1, but we don't know if a.case_id and b.case_id are always the same value for matching rows (they might not be; and if they are always the same, then we just identified a potential redundancy).
There are two ways to fix this for sure.
(1) Move b.case_id = 1 into the left join condition:
left join address_details b on a.street_no = b.street_no and b.case_id = 1
(2) Keep b.case_id = 1 in the WHERE but also allow for NULLED-out b values:
left join address_details b on a.street_no = b.street_no
where b.case_id = 1
or b.street_no IS NULL
Personally I'd go for (1) because that is the most clear way to express that you want to filter b on two conditions, without affecting the rows of a that are being returned.
I do think that Wilhelm Poggenpohl answer is kind of right. You just need to change the last join condition a.case_id=1 to b.case_id=1
select a.* , b.address
from customer_details a
left join address_details b on a.street_no=b.street_no
and b.case_id=1
This query will show every row from customer_details and the corresponding adress if there is a match of street_no and the adress meets the condition case_id=1.
This is because of the where clause. Try this:
select a.* , b.address
from customer_details a
left join address_details b on a.street_no=b.street_no
and a.case_id=1

How to get record not joined result PostgreSQL

I have
table customer {ID(primary key-autoincrement),CUSTOMERNAME}
table item {ID (primary Key-autoincrement),PRODUCT,PRICE}
table price {ID (primary key-autoincrement),CUSTOMERID (foreign key),ITEMID (foreign-key),PRICE}
Now I am filling data like this:
table customer : {1,ABC},{2,DEF}
table item :{1,EGG,50},{2,BRUSH,100},{3,SHOES,290},{4,SOCKS,120},{5,PILLOW,200}
table price :{1,1,3,320}
If I get the price for customer ABC (customer ID :1), then will be displayed result like this (5 records):
{1,1,EGG,50},{2,1,BRUSH,100},{3,1,SHOES,320},{4,1,SOCKS,120},{5,1,PILLOW,200}
But if I want to display price for customer DEF, then only displayed 4 records:
{1,1,EGG,50},{2,1,BRUSH,100},{4,1,SOCKS,120},{5,1,PILLOW,200}
How can I display the price for item with item ID (3) with default price 290 for customer DEF?
I use left outer join for this case then takes record with joined, then for second case they only returned 4 records.
Here my query (returned 4 records):
SELECT TMP."ID",TMP."IDCUSTOMER",TMI."NAME",
CASE WHEN TMP."PRICE" IS NULL THEN TMI."PRICE" ELSE TMP."PRICE" END AS "CUSTOMPRICE"
FROM mitem TMI
LEFT OUTER JOIN mprice TMP ON TMP."IDITEM"=TMI."ID"
LEFT OUTER JOIN mcustomer TMC ON TMC."ID"=TMP."IDCUSTOMER"
WHERE TMP."IDCUSTOMER"='2' OR TMP."ID" IS NULL
Any idea beside without using UNION to join result?
Use CROSS JOIN.
Like this:
SELECT TMP."ID",TMP."IDCUSTOMER",TMI."NAME",
CASE WHEN TMP."PRICE" IS NULL THEN TMI."PRICE" ELSE TMP."PRICE" END AS "CUSTOMPRICE"
FROM mitem TMI
CROSS JOIN mcustomer TMC
LEFT OUTER JOIN mprice TMP ON TMP."IDITEM"=TMI."ID"
AND TMP."IDCUSTOMER"= TMC."ID" AND TMP."IDCUSTOMER"= '2'
WHERE TMC."ID" = '2'

Left join with logic / condition

My title is a bit ambigious but I'll try to clarify below.
I've created a view (A) with a couple of joins. I'm trying to join that view with another view (B). Both views contain a year field, Company ID, Industry ID and a, let's call it, Product code that takes a value of I or U.
View B also contains employee ID, natrually there are multiple employee IDs for every Company ID. Any employee ID could have a Product code that is I, U or both. If it has both there will be 2 identical employee IDs distiguished by the produc code.
Now I want to join view A on Year, Customer ID, Industry ID and Product Code. BUT, since every Customer ID in view B could occure twice (if the underlying employees for that customer have both product code I and U) I only want to join once.
This is the distribution of Customer IDs for Product Codes:
I and NOT U: 165'370
U and NOT I: 45'27
U and I : 48'920
left join [raw].[ViewA] a on a.year=b.year and a.CustomerID=b.CustomerID
and a.IndustryID=b.IndustryID and a.ProductCode ='I'
This is the join I'm running with currently, though I'm excluding all records where the CustomerID only have product code U. The reason why I want to only join once per Customer ID/Year/IndustryID is because I'm later on aggregating some other value from View A. Thus, I can't have that value appear twice.
Current result
Year CustomerID IndustyID ProductCode Value
2015 A Z I 50
2015 A Z U NULL
2015 B Z I 40
2016 A Z I 20
2016 B Z U NULL
What I'd like
Year CustomerID IndustyID ProductCode Value
2015 A Z I 50
2015 A Z U NULL
2015 B Z I 40
2016 A Z I 20
2016 B Z U 30
If I understand correctly, try something as following
[pseudocode]
left join ( Select *, rank() over (partition by whatMakesItUnique Order by ProductCode) distinction From tableA ) a
on your conditions + a.distinction = 1
The idea is to assign number 1 either if there are 2 rows for whatMakesItUnique to ProductCode "I" or to "U" when there is only one row and then join on this assigned number
"whatMakesItUnique" are probably columns Year, CustomerID, IndustyID in your case.
I think you can do what you want with outer apply:
outer apply
(select top (1) a.*
from [raw].[ViewA] a
where a.year = b.year and a.CustomerID = b.CustomerID and
a.IndustryID = b.IndustryID
order by (case a.ProductCode when 'I' then 1 when 'U' then 2 else 3 end)
) a
This will return one row from ViewA, prioritized by the product code.

pad database out with NULL criteria

If I have the following sample table (order by ID)
ID Date Type
-- ---- ----
1 01/01/2000 A
2 22/04/1995 A
2 14/02/2001 B
Where you can immediate see that ID=1 does not have a Type=B, but ID=2 does. What I want to do, if fill in a line to show this:
ID Date Type
-- ---- ----
1 01/01/2000 A
1 NULL B
2 22/04/1995 A
2 14/02/2001 B
where there could potentially be 100's of different types, (so may need to end up inserting 100's rows per person if they lack 100's Types!)
Is there a general solution to do this?
Could I possibly outer join the table on itself and do it that way?
You can do this with a cross join to generate all the rows and a left join to get the actual data values:
select i.id, s.date, t.type
from (select distinct id from sample) i cross join
(select distinct type from sample) t left join
sample s
on s.id = i.id and
s.type = t.type;

Remove Duplicates from LEFT OUTER JOIN

My question is quite similar to Restricting a LEFT JOIN, with a variation.
Assuming I have a table SHOP and another table LOCATION. Location is a sort of child table of table SHOP, that has two columns of interest, one is a Division Key (calling it just KEY) and a "SHOP" number. This matches to the Number "NO" in table SHOP.
I tried this left outer join:
SELECT S.NO, L.KEY
FROM SHOP S
LEFT OUTER JOIN LOCATN L ON S.NO = L.SHOP
but I'm getting a lot of duplicates since there are many locations that belong to a single shop. I want to eliminate them and just get a list of "shop, key" entries without duplicates.
The data is correct but duplicates appear as follows:
SHOP KEY
1 XXX
1 XXX
2 YYY
3 ZZZ
3 ZZZ etc.
I would like the data to appear like this instead:
SHOP KEY
1 XXX
2 YYY
3 ZZZ etc.
SHOP table:
NO
1
2
3
LOCATION table:
LOCATION SHOP KEY
L-1 1 XXX
L-2 1 XXX
L-3 2 YYY
L-4 3 YYY
L-5 3 YYY
(ORACLE 10g Database)
You need to GROUP BY 'S.No' & 'L.KEY'
SELECT S.NO, L.KEY
FROM SHOP S
LEFT OUTER JOIN LOCATN L
ON S.NO = L.SHOP
GROUP BY S.NO, L.KEY
EDIT Following the update in your scenario
I think you should be able to do this with a simple sub query (though I haven't tested this against an Oracle database). Something like the following
UPDATE shop s
SET divnkey = (SELECT DISTINCT L.KEY FROM LOCATN L WHERE S.NO = L.SHOP)
The above will raise an error in the event of a shop being associated with locations that are in multiple divisions.
If you just want to ignore this possibility and select an arbitrary one in that event you could use
UPDATE shop s
SET divnkey = (SELECT MAX(L.KEY) FROM LOCATN L WHERE S.NO = L.SHOP)
I had this problem too but I couldn't use GROUP BY to fix it because I was also returning TEXT type fields. (Same goes for using DISTINCT).
This code gave me duplicates:
select mx.*, case isnull(ty.ty_id,0) when 0 then 'N' else 'Y' end as inuse
from master_x mx
left outer join thing_y ty on mx.rpt_id = ty.rpt_id
I fixed it by rewriting it thusly:
select mx.*,
case when exists (select 1 from thing_y ty where mx.rpt_id = ty.rpt_id) then 'Y' else 'N' end as inuse
from master_x mx
As you can see I didn't care about the data within the 2nd table (thing_y), just whether there was greater than zero matches on the rpt_id within it. (FYI: rpt_id was also not the primary key on the 1st table, master_x).