Converting currency in MySQL using a join - mysql

I have two tables:
A currency table (based on USD) which is updated constantly:
+----+----------+-----------+
| id | currency | value_usd |
+----+----------+-----------+
| 1 | USD | 1 |
| 2 | AUD | 1.077315 |
| 3 | GBP | 0.620868 |
| 4 | EUR | 0.775338 |
+----+----------+-----------+
And I have an order table where new orders are added:
+----+-------------+----------+
| id | sales_total | currency |
+----+-------------+----------+
| 1 | 100 | USD |
| 2 | 50 | GBP |
| 3 | 75 | EUR |
| 4 | 60 | GBP |
+----+-------------+----------+
I have an input of currency, which dictates the type of currency that I need to output the totals in, even though all orders are stored in various currencies.
For example, if $currency = 'EUR'; all totals must be in EUR when querying the order table based on the rates in the currency table. Like so:
+----+-------------+----------+-----------------+
| id | sales_total | currency | converted_total |
+----+-------------+----------+-----------------+
| 1 | 100 | USD | 77.53 |
| 2 | 50 | GBP | 62.44 |
| 3 | 75 | EUR | 75.00 |
| 4 | 60 | GBP | 74.92 |
+----+-------------+----------+-----------------+
How can I do this? I imagine that I'd need some sort of a CASE statement?

This oughta do it:
SELECT o.*, sales_total * (c2.value_usd / c1.value_usd) as converted_total,
c2.currency as converted_currency
FROM `order` o
JOIN `currency` c1 ON o.currency = c1.currency
JOIN `currency` c2 ON c2.currency = 'EUR'
Hard to test without a sample DB though - the calculation might be off but the principle is clear.

The factor for output currency you can get with a Sub-SELECT and the rest you do by joining the Tables on currency:
SELECT
t2.id AS id,
t2.sales_total AS sales_total,
t2.currency AS currency,
(t2.sales_total / value_usd * (SELECT value_usd FROM t1 WHERE currency = 'EUR')) AS converted_total
FROM t2 JOIN t1
ON t1.currency = t2.currency

Related

SQL Join - Limit to base table

I have 4 tables that I want to link together based on the information in the sales_details table which will serve as the base table (limiting results based on the sales_details table)
1)I want to pull all columns from the sales_detail table that are mastercard orders but since the sales_detail table doesn't have a column to identity the type of transaction it is, I have to:
link the sales_detail table to the sales_total table by transaction_ID to get the pay_id
use the pay_id from the sales_total table and link to payment type table in order to filter for payment type
link product_id from sales_detail table to product_detail table to get product name
BASE TABLE : sales_detail
+-------+-----------+-----------+-----------------------------------------+
| order_date | transaction_id| product_cost | product_id | country
+-------+-----------+-----------+------------------------------------------+
| 10/1 | 12345 | 20 | 87956666 | usa
| 10/1 | 12345 | 50 | 63333333 | usa
| 10/5 | 82456 | 50 | 63333333 | usa
| 10/9 | 64789 | 30 | 45665466 | canada
| 10/12 | 08546 | 19 | 78979879 | usa
| 10/15 | 87988 | 19 | 78979879 | usa
| 10/17 | 65898 | 50 | 63333333 | canada
+-------+-----------+-----------+-------------------------------------+
table : payment_type
+-------+-----------+-----------+-------------------+
| pay_id | pay_type| payment | phone_number
+-------+-----------+-----------+-------------------+
| 08585 | 24 | mastercard |214-444-1234 |
| 07895 | 35 | visa |555-111-1234 |
| 08585 | 24 | mastercard |214-444-1234 |
| 08657 | 35 | visa |817-333-1234 |
| 02345 | 24 | mastercard |214-555-1234 |
| 02245 | 35 | visa |888-555-1234 |
| 08785 | 24 | mastercard |240-555-1234 |
| 06587 | 24 | mastercard |240-555-1234 |
+-------+-----------+-----------+-------------------+
table : sales_total
+-------+-----------+-----------+----------+
| pay_id | transaction_id| unit sold |
+-------+-----------+-----------+----------+
| 08585 | 12345 | 2 |
| 07895 | 82456 | 1 |
| 08657 | 64789 | 1 |
| 04568 | 32145 | 3 |
| 02345 | 08546 | 1 |
| 08785 | 87988 | 1 |
| 06587 | 65898 | 1 |
+-------+-----------+-----------+-----------+
table : product_detail
+-------+-----------+-----------+--+
| product_name | product id
+-------+-----------+-----------+--+
popcorn | 87956666
cheetos | 63333333
soda | 93333333
milk | 45665466
| water | 78979879
+-------+-----------+-----------+--+
**I want the output to look something like this: **
IDEAL OUTPUT
+-------+-----------+-----------+--------------------------------------------+
| order_date | transaction_id| product_cost | product_id | product |
+-------+-----------+-----------+--------------------------------------------+
| 10/1 | 12345 | 20 | 87956666 | popcorn |
| 10/1 | 12345 | 50 | 63333333 | cheetos |
| 10/12 | 08546 | 19 | 78979879 | water |
| 10/15 | 87988 | 19 | 93333333 | soda |
+-------+-----------+-----------+--------------------------------------------+
im trying to get all orders from the sales_detail table that have paid by mastercard and from the usa. I tried using left joins and not only it takes forever because of the large tables (doesnt even load) and it also gives me duplicates. What am i doing wrong?
This is the code i used but failed as it took over 20+hrs and timed out:
select t1.order_date,
t1.transaction_id,
t1.product_cost,
t1.product_id
t4.product_name
from sales_detail t1
left join sales_total t2 on t1.transaction_id=t2.transaction_id
left join payment_type t3 on t2.pay_id=t3.pay_id
left join product_detail t4 on t1.product_id=t4.product_id
where t1.order_date between '2020-10-1' and'2020-12-30'
and t1.country not in ('canada')
and t3.pay_type= 24;
there is no output for this code as after 20hrs it could never finish :(
Thanks in advance! I am a beginner so still learning the ins and outs of sql! (am using hive)
There is nothing seems to be wrong with your query and the reason you failed could be due to huge data present in sales table I would presume.
How ever lets give it a try by considering few points, as You only need columns from t1 and t4 , I would go for exists rather joining the tables without taking any columns to the select clause and second point , we can do a inner join between t2 and t3 considering t2 will never have a record with value null in pay_id column
select t1.order_date,t1.transaction_id,t1.product_cost,t1.product_id,t4.product_name
from sales_detail t1
left join product_detail t4 on t1.product_id = t4.product_id
where t1.order_date between '2020-10-1' and'2020-12-30'
and t1.country not in ('canada')
and exists (select 1
from sales_total t2
join payment_type t3 on t2.pay_id = t3.pay_id
where t1.transaction_id = t2.transaction_id
and t3.pay_type= 24);
If you still face performance issue try creating index on "transaction_id" and "product_id ".
I hope this help you taking a step forward. Thanks.
Missing comma after t1.product_id.
Use country = 'usa' as the country filter instead of not in.
Check the date range.2020-10-1 is Oct of 2020 which is in future.
select
t1.order_date,
t1.transaction_id,
t1.product_cost,
t1.product_id,
t4.product_name
from sales_detail t1
join product_detail t4 on t1.product_id=t4.product_id
join sales_total t2 on t1.transaction_id=t2.transaction_id
join payment_type t3 on t2.pay_id=t3.pay_id
where t1.order_date between ('2020-12-30' and '2020-1-10') and
t1.country = 'usa' and
t3.pay_type= 24;

SQL query to get Net Salse by every month

I'm looking for a query to get monthly net sales I tried this far but I couldn't get what I want.
this is my Order Table
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
| orderID | custID | userID | orderDate | paymentMethod | grossAmount | netAmount | cash | balance |
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
| INV-0001 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 525.00 | 525.00 | 550.00 | 25.00 |
| INV-0002 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 240.00 | 240.00 | 250.00 | 10.00 |
| INV-0003 | CUST-0001 | U-001 | 2020-05-01 | Cash Pay | 220.00 | 220.00 | 250.00 | 30.00 |
| INV-0004 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 895.00 | 895.00 | 1000.00 | 105.00 |
| INV-0005 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 300.00 | 300.00 | 500.00 | 200.00 |
| INV-0006 | CUST-0001 | U-001 | 2020-04-30 | Cash Pay | 230.00 | 230.00 | 250.00 | 20.00 |
+----------+-----------+--------+------------+---------------+-------------+-----------+---------+---------+
This is my CustomerReturn Table
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
| retID | orderID | itemCode | userID | retDate | returnQty | unitPrice | totalAmount |
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
| 1 | INV-0001 | 1800232050 | U-001 | 2020-05-01 | 1.00 | 100.00 | 100.00 |
| 2 | INV-0002 | 1909873674 | U-001 | 2020-05-01 | 2.00 | 55.00 | 110.00 |
| 3 | INV-0004 | 1800232050 | U-001 | 2020-04-30 | 1.00 | 100.00 | 100.00 |
+-------+----------+------------+--------+------------+-----------+-----------+-------------+
the formula is (total of the monthly bill(Order.netAmount) - a total of monthly return (CustomerReturn.totalAmount))
in need to get net sales every year of every month.
select orderDate,sum(netAmount)-sum(totalAmount) from `Order` o,CustomerReturn r where o.orderID=r.orderID GROUP BY orderDate;
when I run this query it shows me this
+------------+---------------------------------+
| orderDate | sum(netAmount)-sum(totalAmount) |
+------------+---------------------------------+
| 2020-04-30 | 795.00 |
| 2020-05-01 | 555.00 |
+------------+---------------------------------+
but it should be Like this
+------------+---------------------------------+
| orderDate | sum(netAmount)-sum(totalAmount) |
+------------+---------------------------------+
| 2020-04-30 | 1425.00 |
| 2020-05-01 | 775.00 |
+------------+---------------------------------+
please help me. Thank you.!
Your query is good, it is fetching all records when there is a match on OrderId in the table CustomerReturn and doing the sums as you requested, however there are no returns for the order INV-0003, so this condition o.orderID=r.orderID is not valid when it comes to that record and it is ignoring that data. Doing a left join will fix the issue.
select
o.orderDate,
sum(o.netAmount)-sum(case when cr.totalAmount is null then 0 else cr.totalAmount end)
from
Orders o
left join
CustomerReturn cr
on
o.orderID = cr.orderID
group by
o.orderDate
A left join will cause cr.totalAmount to have null values in case there is no match for o.orderID=r.orderID then we use this part; case when cr.totalAmount is null then 0 else cr.totalAmount end to fix that null issue.
Because you are joining on dates that is why you are not getting correct answer, as order date and return date can have different month.
Better if you extract the month and then do sum as shown in below query, and here is the demo.
select
o.mm as month,
sum(total_net_amount - total_amount) as total
from
(
select
month(orderDate) as mm,
sum(netAmount) as total_net_amount
from Orders
group by
month(orderDate)
) o
join
(
select
month(retDate) as mm,
sum(totalAmount) as total_amount
from CustomerReturn
group by
month(retDate)
) cr
on o.mm = cr.mm
group by
o.mm
Output:
*--------------*
|month | total |
*--------------*
| 5 | 775 |
| 4 | 1325 |
*--------------*
Learn to use proper, explicit, standard, readable JOIN syntax. As pointed out in another answer, you want a LEFT JOIN. That said, the simpler way to write the logic is:
select o.orderDate,
sum(o.netAmount)- coalesce(sum(cr.totalAmount, 0)) as net_amount
from Orders o left join
CustomerReturn cr
on o.orderID = cr.orderID
group by o.orderDate;

Only display Card payments

I designed a till system about 6 years ago, and while the code is dismal and horrible to look at, it is still going and the cafe I designed it for has been using it all this time.
However, they have recently acquired a card machine, and so now when they want to view all the sales for the day they wnat to see cash vs card in two separate tables.
This is proving tricky and the SQL for it is stumping me - I can't get my head around it.
Here are the tables involved:
categories
+----+-------------------+---------+------------+
| id | name | display | ts |
+----+-------------------+---------+------------+
| 1 | Drinks | 1 | 2016-10-14 |
| 2 | General Snacks | 1 | 2016-10-14 |
| 3 | Lunch Options | 1 | 2016-10-14 |
| 4 | Conference Drinks | 1 | 2016-10-14 |
+----+-------------------+---------+------------+
products
+----+-----------------+-------+------+-----+---------+------------+
| id | name | price | cost | cID | display | ts |
+----+-----------------+-------+------+-----+---------+------------+
| 1 | English Tea | 0.6 | 0.09 | 1 | 1 | 2018-02-15 |
| 2 | Speciality Teas | 0.8 | 0.17 | 1 | 1 | 2018-02-15 |
| 3 | Crisps | 0.6 | 0.41 | 3 | 1 | 2018-02-15 |
| 4 | Chocolate Bar | 0.6 | 0.5 | 3 | 1 | 2018-02-15 |
+----+-----------------+-------+------+-----+---------+------------+
receipts
+----+-----+-----+----------+------------+
| id | oID | pID | quantity | ts |
+----+-----+-----+----------+------------+
| 1 | 1 | 26 | 1 | 2013-11-21 |
| 2 | 2 | 6 | 2 | 2013-11-21 |
| 3 | 3 | 2 | 1 | 2013-11-21 |
| 4 | 4 | 3 | 1 | 2013-11-21 |
+----+-----+-----+----------+------------+
sales
+----+-------+----------+------+------+--------+------------+
| id | total | tendered | flag | card | userID | ts |
+----+-------+----------+------+------+--------+------------+
| 1 | 1 | 1 | 0 | 0 | 4 | 2013-11-21 |
| 2 | 2 | 2 | 0 | 0 | 4 | 2013-11-21 |
| 3 | 0.6 | 0.6 | 0 | 0 | 4 | 2013-11-21 |
| 4 | 0.6 | 0.6 | 0 | 0 | 4 | 2013-11-21 |
+----+-------+----------+------+------+--------+------------+
Please bear in mind that I wrote this a long time ago and I'm aware that its not perfect. Just to explain the above, oID stands for orderID but really should be salesID and links to the sales table ID, and pID stands for productID and is a foreign key linking to the products table. Similarily, cID is really categoryID.
Okay So the cafe manager had requested a table that looks like the following:
+---------------+-----+------+-------+------------+-----------+
| Drinks | Qty | Cost | Price | Cost-Total | Qty-total |
+---------------+-----+------+-------+------------+-----------+
| Juice Carton | 2 | 33p | 60p | 66p | £1.20 |
| Filter Coffee | 11 | 20p | 80p | £2.20 | £8.80 |
| Sub Total | 13 | | | £2.86 | £10.00 |
| Grand Total | 13 | | | £2.86 | £10.00 |
+---------------+-----+------+-------+------------+-----------+
Which has been fine, I've used the following SQL statement to produce this:
SELECT
categories.name AS category, products.name, pID,
(SELECT SUM(quantity) FROM receipts s WHERE s.pID = r.pID AND DATE(s.ts) = CURDATE()) AS quantity,
products.price,
products.cost
FROM receipts r
LEFT JOIN products ON r.pID = products.id
LEFT JOIN categories ON products.cID = categories.id
WHERE DATE(r.ts) = CURDATE()
GROUP BY r.pID ORDER BY categories.name;
However now I need to display two tables, one for card and one for cash. Now the card payments are marked in the sales table with a 1 in the card column. So I tried writing this:
SELECT
categories.name AS category, products.name, pID,
(SELECT SUM(quantity) FROM receipts s WHERE s.pID = r.pID AND DATE(s.ts) = CURDATE()) AS quantity,
products.price,
products.cost
FROM receipts r
LEFT JOIN products ON r.pID = products.id
LEFT JOIN sales x on r.oID = x.id
LEFT JOIN categories ON products.cID = categories.id
WHERE DATE(r.ts) = CURDATE() AND x.card = 1
GROUP BY r.pID ORDER BY categories.name;
However it is just displaying the same data as the first query. I know where the problem is - its in the embedded SELECT statement (AS quantity), as I'm not specifying in there whether its a card payment or a cash payement. I thought that just by adding x.card = 1 a the end would do it, but evidentally not.
Can anyone help me fix this SQL problem? How can I get the card condition into the embedded SQL, as it is retrieving from receipts and receipts does not hold information as to wether its a card payment or not?
I'm lost as to how to proceed really. All help will be appreciated!
In it's basic form:
SELECT * FROM Sales WHERE card = 1
Will display just the card payments
This will give you any sales from today:
SELECT *
FROM
categories,
products,
sales,
reciepts,
LEFT JOIN
products ON reciepts.pID
sales ON reciepts.oID
categories ON products.cID
WHERE DATE(s.ts) = CURDATE()
AND sales.card = 1
`
So what you have there is correct. It's something else you are missing...
From what I can see so far you haven't selected the sales table which could be your issue.
Have you tried running the code in SQL management studio and seeing what the result is?

calculating accounts balance from debit and credit table

I have a accounts table like this
+-----------+--------------+
| fld_id| name |
+-----------+--------------+
| 1 | Bank1|
| 2 | Bank2|
| 4 | Bank3|
+-----------+--------------+
Revenue Income Table Like this
+-----------+--------------+---------------+-------------+
| fld_id | fld_type | fld_account id| fld_amount |
+-----------+--------------+---------------+-------------+
| 1 | Salry| 1 | 400 |
| 2 | Rent | 2 | 500 |
| 4 | Others | 1 | 1000 |
+-----------+--------------+---------------+-------------+
Payment Table Like This
+-----------+--------------+---------------+-------------+
| fld_id | fld_type | fld_account id| fld_amount |
+-----------+--------------+---------------+-------------+
| 1 | Food | 2 | 200 |
| 2 | Entertain | 2 | 300 |
| 4 | Transport | 1 | 400 |
+-----------+--------------+---------------+-------------+
I want a final balance table for accounts with sum of income, expence and balance like This Table --
+-----------+--------------+---------------+-------------+
| account | Income | Expence | Balance |
+-----------+--------------+---------------+-------------+
| Bank1 | 1400 | 400 | 1000 |
| Bank2 | 500 | 500 | 0 |
| Bank3 | 0 | 0 | 0 |
+-----------+--------------+---------------+-------------+
So far I write this query and getting income and expense but did't find any way to calculate balance, my query and result is --query
SELECT fld_account as account, Income, Expense
from tbl_accounts
LEFT JOIN (SELECT fld_account_id, SUM(fld_amount) as Income FROM tbl_revenue tr GROUP BY tr.fld_account_id) tc on fld_id=tc.fld_account_id
left JOIN (SELECT fld_account_id, SUM(fld_amount) as Expense FROM tbl_payment tp GROUP BY tp.fld_account_id) td on fld_id=td.fld_account_id
and the result is like below --
+-----------+--------------+---------------+
| account | Income | Expense |
+-----------+--------------+---------------+
| Bank1 | 1400 | 400 |
| Bank2 | 500 | 500 |
| Bank3 | Null | Null |
+-----------+--------------+---------------+
How can I calculate balance form payment and revenue table and join it with my account table? Any help is very appreciated.
Just use coalesce():
SELECT fld_account as account, COALESCE(Income, 0) as Income,
COALESCE(Expense, 0) as Expense,
( COALESCE(Income, 0) - COALESCE(Expense, 0) ) as balance
FROM tbl_accounts LEFT JOIN
(SELECT fld_account_id, SUM(fld_amount) as Income
FROM tbl_revenue tr
GROUP BY tr.fld_account_id
) tc
ON fld_id = tc.fld_account_id LEFT JOIN
(SELECT fld_account_id, SUM(fld_amount) as Expense
FROM tbl_payment tp
GROUP BY tp.fld_account_id
) td
ON fld_id = td.fld_account_id;
COALESCE() is the ANSI-standard function that returns the first non-NULL argument.

Join self-join table with another table

I have two tables: products and meta.
Products table:
+----+----------+
| id | name |
+----+----------+
| 1 | TV |
| 2 | Computer |
| 3 | Freezer |
+----+----------+
Meta table:
+----+------------+-----------+------------+
| id | product_id | meta_key | meta_value |
+----+------------+-----------+------------+
| 1 | 1 | currency | USD |
| 2 | 1 | price | 1100 |
| 3 | 2 | currency | PLN |
| 4 | 2 | price | 9300 |
| 5 | 3 | currency | USD |
| 6 | 3 | price | 1200 |
+----+------------+-----------+------------+
now the following query works fine:
select price.product_id, products.name, price.meta_value as 'price', currency.meta_value as 'currency'
from meta as price
join meta as currency on(price.product_id=currency.product_id and currency.meta_key='currency')
join products on(products.id=price.product_id)
where price.meta_key='price';
result:
+------------+----------+-------+----------+
| product_id | name | price | currency |
+------------+----------+-------+----------+
| 1 | TV | 1100 | USD |
| 2 | Computer | 9300 | PLN |
| 3 | Freezer | 1200 | USD |
+------------+----------+-------+----------+
but the query:
select price.product_id, products.name, price.meta_value as 'price', currency.meta_value as 'currency'
from meta as price, meta as currency
join products on(products.id=price.product_id)
where
price.product_id=currency.product_id
and price.meta_key='price'
and currency.meta_key='currency';
returns: "Unknown column 'price.product_id' in 'on clause'"
Why does that happen ?
Your "from" clause is interpreted as:
from meta as price, (meta as currency join products on (products.id = price.product_id)
So, there is no price.product_id available to the on clause, as it only knows about the meta as currency and products tables.