Finding total cost of road - mysql

I have a table with 3 columns source, dest, total cost and have values like
Agra Delhi 500
Agra Kanpur 400
Delhi Agra 900
Kanpur Agra 500
I want total cost like
Agra<-->Delhi 1400
Agra<-->Kanpur 900

You can use LEAST() and GREATEST() functions, and a GROUP BY query:
SELECT
LEAST(source, dest),
GREATEST(source, dest),
SUM(total_cost)
FROM
tablename
GROUP BY
LEAST(source, dest),
GREATEST(source, dest)

SELECT a.source, a.dest, (a.total_cost + b.total_cost) round_trip_cost
FROM my_tab as a
LEFT OUTER JOIN my_tab as b
ON (a.source = b.dest AND b.source = a.dest)

Related

How to filter the result where >80% of the transaction coming from the same customer?

I have a transaction table like this:
tr_id merchant customer amount
-------------------------------------
00001 2005 3002 20
00002 2006 3002 11.16
00003 2001 3007 17.91
00004 2005 3002 20
00005 2003 3003 13.23
00005 2006 3007 14.61
00006 2005 3002 20
Etc.
I want to know the query to find which merchant that have >80% of the transaction coming from the same customer.
The result should contain list of merchant, customer in question, and each with sum of amount.
Try this:
select c.merchant, customer, 100 * customer_total / merchant_total as percentage
from (select merchant, customer, sum(amount) as customer_total
from mytable
group by merchant, customer) c
join (select merchant, sum(amount) as merchant_total
from mytable
group by merchant) m
on m.merchant = c.merchant
and customer_total > .8 * merchant_total
See live demo.
You could change and to where if you feel it improves readability, at a possible small cost to performance.
Group the table once by merchant to calculate the total records of
each merchant
Once again, group the table by merchant and customer to calculate
the total records of each merchant and customer
Join the result and calculate the percentage
query :
SELECT
t2.merchant,
t2.customer,
CONCAT((CAST(t2.merchant_Customer_CuontItem AS FLOAT) / CAST(t1.merchant_CuontItem AS FLOAT)) * 100, '%') AS newCol
FROM
(SELECT merchant,COUNT(*) AS merchant_CuontItem FROM tb GROUP BY merchant) t1
JOIN
(SELECT merchant,customer ,COUNT(*) AS merchant_Customer_CuontItem FROM tb GROUP BY merchant,customer) t2
ON t1.merchant = t2.merchant
Demo in db<>fiddle

How to avoid Group By working on every output?

I have a table like this:
LocationID CountryName CustomerAmount
C01 Australia 500
C02 Australia 200
C03 China 100
C04 China 200
C05 Japan 50
C06 Canada 120
I want to find the "number of customers in each country" AND the total number of customers.
Now I have the following query:
select countryName, sum(CustomerAmount)
from test
group by countryName;
I obviously got this output:
CountryName. customerAmount
Australia 700
China 300
Japan 50
Canada 120
But I want the output like this
CountryName. customerAmount totalAmount
Australia 700 1170
China 300 1170
Japan 50 1170
Canada 120 1170
My problem is how can I put two same sum(customerAmount) side by side, but one is grouped by countryName, while the other just sum up all values in customerAmount table.
Thank you in advance!!!! I have to say sorry as my expression may be ambiguous.
One easy way is just to use a sub-query like
select countryName, sum(CustomerAmount) customerAmount,
(select Sum(customerAmount) from test) totalAmount
from test
group by countryName;
If you can use window functions (MySql 8+) you can do
select countryName, sum(CustomerAmount) customerAmount,
sum(Sum(CustomerAmount)) over() totalAmount
from test
group by countryName;
note the nested sum().
SELECT countryName, SUM(CustomerAmount), SUM(CustomerAmount) OVER()
FROM test
GROUP BY countryName;
I did not test this, but using the over clause should do what you are looking for as seen here.

SQL to get distinct record for a combination of two column (Irrespective of order)

Consider the below Table structure and data
CREATE TABLE Distance(
source VARCHAR(20),
destination VARCHAR(20),
distance INTEGER
);
Select * from Distance;
source destination distance
======= =========== ======
Chennai Mumbai 500
Mumbai Chennai 500
Mumbai Bangalore 500
Bangalore Mumbai 500
Goa Mumbai 100
Mumbai Goa 100
Kolkata Goa 1000
I need the output to have single record for 2 cities if repeating, i,e, any one record among the below 2 is fine.
Chennai Mumbai 500
Mumbai Chennai 500
Expected o/p:
source destination distance
======= =========== ======
Chennai Mumbai 500
Mumbai Bangalore 500
Goa Mumbai 100
Kolkata Goa 1000
Here is one method using least() and greatest():
select least(source, destination), greatest(source, destination), max(distance)
from distance
group by least(source, destination), greatest(source, destination);
This has the disadvantage that you could return a row not in the table. For instance, if you had a single row with "Mumbai/Chennai/500", then this query would return "Chennai/Mumbai/500" -- and this row is not in the original table.
So, an alternative method is:
select source, destination, distance
from distance
where source < destination
union all
select destination, source, distance
from distance d
where source > destination and
not exists (select 1
from distance d2
where d2.source = d.destination and d2.destination = d.source
);
This version is also ANSI-compatible and should work in all databases.
If you need to preserve the order of columns you might use
SELECT *
FROM Distance t1
WHERE NOT EXISTS
(
SELECT * FROM Distance t2
WHERE t1.destination = t2.source
AND t1.source = t2.destination
AND t1.destination > t2.destination
);
When multiple rows per source/combination exist you must either add DISTINCT or a GROUP BY.
SELECT DISTINCT LEAST(source,destination) a
, GREATEST(source,destination) b
, distance
FROM distance;
select
(case when source>destination then source else destination end) as src,
(case when source<destination then source else destination end) as dstn,
distance from distance
The following logic seems much easier and easy to understand and does the same work.
select a.source,a.destination,a.distance as distance from
distance a join distance b on a.destination = b.source and b.destination = a.source
and a.source < b.source
union all
select a.source,a.destination,a.distance from distance a left join distance b
on a.destination = b.source and b.destination = a.source
where b.source is NULL ;

Find distinct combination of stations in table

I have a table with sample data below. Want to know distinct combination of stations present in table.
Table Name: train_route
FROM_STN TO_STN DISTANCE
BLR CHENNAI 800
DEL MUMBAI 1500
VNS DEL 1000
MUMBAI DEL 1497
CHENNAI BLR 798
Distances might be different in different records for same stations. I want to know all the distinct combination of stations present in table.
For ex: For above sample desired output will be
FROM_STN TO_STN
BLR CHENNAI
DEL MUMBAI
VNS DEL
The actual table is having billions of records. Anything that can be done using self join?
select tr.* from
(
select from_stn as frs, to_stn as tos
from train_route
union
select to_stn, from_stn
from train_route) t
join train_route tr on t.frs = tr.from_stn and t.tos = tr.to_stn
You can use union to remove duplicates.
If only the distinct combinations and not which station is the to or from is important you can just do a lexical comparison and swap place so that lower station always shows up in the first column and then do a group by:
select
if(FROM_STN < TO_STN, FROM_STN, TO_STN) station1,
if(FROM_STN > TO_STN, FROM_STN, TO_STN) station2
from
train_route
group by
if(FROM_STN < TO_STN, FROM_STN, TO_STN),
if(FROM_STN > TO_STN, FROM_STN, TO_STN);
This would give you a result like:
| station1 | station2 |
|----------|----------|
| BLR | CHENNAI |
| DEL | MUMBAI |
| DEL | VNS |
Sample SQL Fiddle
Another solution that might perform better (depending on keys and indexes):
select distinct from_stn, to_stn
from
(
select from_stn, to_stn from train_route
union all
select to_stn, from_stn from train_route
) all_pairs
where from_stn < to_stn;
In the end I don't think there's any way around having to do a lexical comparison.
Thanks for all the answers.
I have got solution for my question. Just wanted to share with you all.
select a.from_stn,a.to_stn
from train_route a
left join train_route b
on a.from_stn=b.to_stn and a.to_stn=b.from_stn
where a.from_stn<=coalesce(b.from_stn,a.from_stn);

How to (MySQL) multiply columns and then the sum rows?

I've got this table:
id | payment_id | quantity | unit cost
1 633 1 750
2 633 1 750
3 632 2 750
4 632 2 750
What I need is :
payemnt_id | total
633 1500
632 3000
You can also think of this as Countries and then you are trying to find the total for each Country. I was sure there were some tutorials like this but could not find by STFW.
You can simply put the formula (expression) inside SUM:
SELECT payment_id, SUM(`unit cost` * quantity) AS total
FROM myTable
GROUP BY payment_id
SELECT
payment_id,
SUM(subtotal) AS total
FROM(
SELECT
payment_id,
(unit_cost * quantity) AS subtotal
) AS t1
GROUP BY
payment_id
SELECT payemnt_id, SUM(`unit cost` * quantity) as total
FROM Table1
GROUP BY payemnt_id
SELECT COALESCE (SUM(cost_field * quantity_field),0) AS tot FROM Table_Name
I Think This One Is Good, Why ?
Because If Their is No Result It Will Give You Zero