MYSQL How to get rid of duplicates - mysql

I need the sum of two customers each so I wrote the following query:
SELECT m.m_name, m2.m_name AS m_name2, SUM(m.price + m2.price) as total_amount, rn.name
FROM
(
SELECT m.name AS m_name, m.id AS m_id ,IFNULL(SUM(d.num * p.price), 0) AS price
FROM m_member as m
LEFT JOIN t_sales AS t ON m.id = t.m_id
INNER JOIN m_product as p
LEFT JOIN t_sales_detail as d ON t.id = d.id AND p.id = d.p_id
GROUP BY m.id
)AS m
LEFT JOIN
(
SELECT m.name AS m_name, m.id AS m2_id ,IFNULL(SUM(d.num * p.price), 0) AS price
FROM m_member as m
LEFT JOIN t_sales AS t ON m.id = t.m_id
INNER JOIN m_product as p
LEFT JOIN t_sales_detail as d ON t.id = d.id AND p.id = d.p_id
GROUP BY m.id
) AS m2 ON m.m_id != m2.m2_id
JOIN m_lank AS rn ON (SELECT SUM(m.price + m2.price)) BETWEEN rn.low_limit AND rn.up_limit
GROUP BY m.m_id, m2.m2_id
order by total_amount;
The results looks like this:
# m_name m_name2 total_amount name
Nagayama Kawata 380 Bronze
Kawata Nagayama 380 Bronze
Nagaoku Kawata 500 Bronze
Kawata Nagaoku 500 Bronze
Nagayama Nagaoku 880 Bronze
Nagaoku Nagayama 880 Bronze
Kawashima Kawata 2620 Bronze
Kawata Kawashima 2620 Bronze
...
The problem is, I don't need to sum the same customer two times.
How can I get rid of the duplicate results? Anyone has a solution?
EDIT:
I want something like this:
# m_name m_name2 total_amount name
Nagayama Kawata 380 Bronze
Nagaoku Kawata 500 Bronze
Nagayama Nagaoku 880 Bronze
Kawashima Kawata 2620 Bronze
...
Sorry for my poor English. It might be difficult to understand what I need.
Basically I have in total five customers.
Customer A has bought a total of 400$
Customer B has bought a total of 1030$.
Customer C .... 1540$.
Customer D .... 0$.
Customer F .... 320$.
Now I want to sum every customer with each other:
A + B
A + C
A + D
A + F
B + C
B + D
B + F
C + D
C + F
D + F

Using a CTE we get to reuse the table user_totals without a duplication:
WITH user_totals AS
(SELECT s.m_id AS id,
sum(sd.num*p.price) AS sales_amount
FROM t_sales_detail sd
JOIN m_product p ON sd.p_id=p.id
JOIN t_sales s ON s.id=sd.id
GROUP BY s.m_id)
SELECT m1.name,
m2.name,
t1.sales_amount+t2.sales_amount
FROM user_totals t1
JOIN user_totals t2 ON t1.id < t2.id
JOIN m_member m1 ON t1.id = m1.id
JOIN m_member m2 ON t2.id = m2.id
Like the other answer greater than/less than is a good JOIN criteria for getting only one match.
!= makes a bad join criteria as you're after a non-match on all rows, it rarely does what you expect.
An illustration of this is fiddle
Note: row limits and IFNULL criteria removed for readabilit

If I understood you correctly, it can be achieved with the minimal change to your query. Just replace != with < or >. Thus you will get each pair only once.
SELECT m.m_name, m2.m_name AS m_name2, SUM(m.price + m2.price) as total_amount, rn.name
FROM
(
SELECT m.name AS m_name, m.id AS m_id ,IFNULL(SUM(d.num * p.price), 0) AS price
FROM m_member as m
LEFT JOIN t_sales AS t ON m.id = t.m_id
INNER JOIN m_product as p
LEFT JOIN t_sales_detail as d ON t.id = d.id AND p.id = d.p_id
GROUP BY m.id
)AS m
LEFT JOIN
(
SELECT m.name AS m_name, m.id AS m2_id ,IFNULL(SUM(d.num * p.price), 0) AS price
FROM m_member as m
LEFT JOIN t_sales AS t ON m.id = t.m_id
INNER JOIN m_product as p
LEFT JOIN t_sales_detail as d ON t.id = d.id AND p.id = d.p_id
GROUP BY m.id
) AS m2 ON m.m_id > m2.m2_id
JOIN m_lank AS rn ON (SELECT SUM(m.price + m2.price)) BETWEEN rn.low_limit AND rn.up_limit
GROUP BY m.m_id, m2.m2_id
order by total_amount;

Related

postgresql group by

This is my query in Postgresql:
SELECT
C.id, S.domen, B.name, C.source_id, ST.name
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
ORDER BY "calltime" LIMIT 50
And I get this result:
Now I am trying to group by name(last column) this result to get result like this:
Контекстная реклама - 17
SEO-10
....
And for this I use this query:
SELECT
ST.name, count(ST.name)
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
GROUP BY ST.name
ORDER BY count(ST.name) DESC LIMIT 50
But I am getting wrong result:
Seems like it take values from source_id column.
what am I doing wrong?
Try this, If you call group by before limit the result then group by for the entire records. So first filter then do the group by.
SELECT
name, count(name)
FROM(
SELECT
ST.name
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
ORDER BY "calltime" LIMIT 50
) T
GROUP BY name
The LIMIT 50 in the second query is executed after the GROUP BY.
If you want to aggregate only the first 50 lines, write the LIMIT 50 into a subselect and perform the GROUP BY in the outer SELECT.
It's possible that the 49 is just a coincidence. Try:
SELECT
ST.name, count(*)
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6') AND
C.source_id > 50
GROUP BY ST.name
ORDER BY count(*) DESC LIMIT 50
All I did was change it to count(*) and add AND C.source_id > 50 to the Where clause. Let's see if this changes the count.
Also you could just run this:
SELECT
count(*)
FROM "calls" C
INNER JOIN "site" S ON S.id=C.site_id
INNER JOIN "sources" ON sources.id=C.source_id
INNER JOIN "brand" B ON B.id = S.id_brand
INNER JOIN "source_types" ST ON ST.id = "sources".type_id
WHERE
("calltime" >= '2017-12-01') AND
("calltime" <= '2017-12-03') AND
(S."id_brand"='6')
This gives you a total count of all the rows (I removed the GROUP BY). If this number equals the total of your grouped row counts, then they really are the counts. We are looking for 127 which is 49 + 30 + 21 + 13 + 9 + 4 + 1
I hope this helps.

Getting result as percentage when using foreign keys

I currently have a DB with 4 table:
Customer
Sale (CustID & RoomID fk)
Room (ManID fk)
Manager
I am trying to get the cities in which the customers reside in as a percentage. However, I only want to show the the customers who made a purchase using a said manager. Currently this comes through as an amount either under or over 100% total.
When this query is isolated to the customer table, the result adds up to 100% correctly, however it does need to be taken from sales using the manager username as a parameter. This is what I currently have:
SELECT
(COUNT(c.city) / (SELECT Count(CustID) FROM Customer) * 100) AS percent, c.city AS City
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'manager123'
GROUP BY c.City;
EDIT:
I wish to add that the CustID may occur more than once within the sales table, additionally, it may be null. Not sure if is required to use distinct when counting.
Having isolated my issue to this, I felt it necessary to mention as I am still unable to exclude these from the result and an incomplete figure (totaling <100% still showing)
Here you go.
SELECT NoCity,COUNT(*)/percent *100 as percentOfCustomerBasedonManager,City
FROM (
SELECT m.UserName,COUNT(c.city) AS NoCity, COUNT(c.CustID) AS percent,c.city AS City FROM
sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
GROUP BY c.City ) cityTable WHERE cityTable.UserName = 'manager123'
This may help:
SELECT city, ((city_count)/(customer_count)*100) as Percent
(
SELECT city, COUNT(*) as city_count, customer_count
FROM
(
SELECT distinct c.city
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'manager123'
GROUP BY c.city
) as t1
LEFT JOIN
(
SELECT city as city2, COUNT(*) as customer_count
FROM
(
SELECT c.city, distinct c.CustID
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'manager123'
GROUP BY c.city
) as t2
) as t3 on t1.city=t3.city2
) as master
GROUP BY city
Ok, here is the solution I came to, with a huge thanks to Lim Neo who pointed me in the right direction.
SELECT
round(COUNT(c.city) /
(
SELECT Count(b.CustID)
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'Manager123'
) * 100)
AS percent, c.city AS City
FROM sale s
INNER JOIN customer c ON s.CustID = c.CustID
INNER JOIN room r ON s.RoomID = r.RoomID
INNER JOIN manager m ON r.ManID = m.ManID
WHERE m.UserName = 'Manager123'
GROUP BY c.City;

inner join 4 tables with group, order by, having clause

I have 4 table and i want to extract: id, nume, localitate, masina_id, nr_inmatriculare, an_fabricatie, rafinarie, marca, and sum (quantity+deliver_quantity) as total_quantity group by an_fabricatie , Order by marca, and put some having clouse.
I don’t know how to make this.
My query is as bellow , but I think isn't correct.
select c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.an_fabricatie,
i.rafinarie, m.marca from clienti c inner join livrari l on c.id = l.id inner join incarcari I on l.incarcare_id = l.livrari_id inner join masina m on i.id_marca = m.id, sum(select quantity, deliver_quantity) as total_quantity group by an_fabricatie having quantity >1000 order by marca;
Incarcari table
Id|livrari_id|id_marca|nr_inmatriculare|an_fabricatie|rafinarie|aviz_incarcare|quantity|
Livrari table
Id|masina_id|client_id|incarcare_id|deliver_quantity|aviz_livrare
Masini table
Id|numar_inmatriculare|marca|an_fabricatie|
Clienti table
Id|nume|localitate|date_add|date_upd|
SELECT c.id, c.nume, c.localitate, l.masina_id, i.nr_inmatriculare, i.an_fabricatie, i.rafinarie, m.marca, (SUM(i.quantity) + SUM(l.deliver_quantity)) AS total_quantity
FROM clienti c
INNER JOIN livrari l ON c.id = l.id
INNER JOIN incarcari i ON l.incarcare_id = i.livrari_id
INNER JOIN masini m ON i.id_marca = m.id
GROUP BY i.an_fabricatie, c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.rafinarie, m.marca
HAVING i.quantity > 1000
ORDER BY m.marca DESC;

MySQL Complex SELECT Query - JOINS

Please find the SQLfiddle URL:
http://sqlfiddle.com/#!2/c8002/1/0
Actual Output should be:
region_id status1 branches balance fses
status0 discount branch_names telecallers
2 NULL 4 400.00 30 KOTTAKKAL 341.00 3 3
2 NULL 4 800.00 31 KALPETTA 394.00 3 3
I'm getting the repeated output as follows:
region_id status1 branches balance fses
status0 discount branch_names telecallers
2 NULL 4 400.00 30 KOTTAKKAL 341.00 3 3
2 NULL 4 400.00 30 KOTTAKKAL 394.00 3 3
2 NULL 4 800.00 31 KALPETTA 341.00 3 3
2 NULL 4 800.00 31 KALPETTA 394.00 3 3
how do I correct the same?
Thanks & Regards,
Manjesh.
I guess you're having a problem in your query structure itself, as it's not simply a request for distinct.
Your joining tables, and retrieving distinct values for each row you have, that you actually wanted to be only one for each of KOTTAKKAL and KALPETTA.
Notice in your example that, although the addition of the clause distinct is performed, no difference will come over, as the rows you have are distinct. In column balance you have both 341.00 and 394.00 for each entry of KOTTAKKAL and KALPETTA.
If using group, yes, you will lose information on balance, as the result return after a group by is only the first of the different elements grouped (in case of a column with multiple values).
You either have to determine what result you want, or cope with having sum other calculation over the column balance.
I guess the result, and the proper join you were willing to do is this:
SELECT DISTINCT E.`region_id`,a0.status0,a1.status1,k.discount,k.branches
,k.branch_names, k.balance,TCLRS.telecallers,FSE.fses
FROM tbl_insurance_excel E
LEFT OUTER JOIN (SELECT E2.region_id, count(`id`) AS status1
FROM tbl_insurance_excel E2 LEFT JOIN tbl_recipt_general_details ON id=insurance_excel_id
JOIN tbl_branches ON policy_closed_branch= branch_id
WHERE E2.`row_status` =1 AND E2.canceled_status='no' AND E2.region_id=2 GROUP BY region_id) a1 ON a1.region_id=E.region_id
LEFT OUTER JOIN (SELECT E2.region_id, count(`id`) AS status0
FROM tbl_insurance_excel E2 LEFT JOIN tbl_recipt_general_details ON id=insurance_excel_id
JOIN tbl_branches ON policy_closed_branch= branch_id
WHERE E2.`row_status` =0 AND E2.canceled_status='no' AND E2.region_id=2 GROUP BY region_id) a0 ON a0.region_id=E.region_id
LEFT JOIN (
SELECT IEX.region_id, B.branch_name AS branch_names, B.branch_id AS branches, sum( DDT.discounts_amount ) AS discount, sum( RGD.`recipt_bal_amount` ) AS balance
FROM tbl_insurance_excel IEX
LEFT JOIN tbl_recipt_general_details RGD ON IEX.id = RGD.insurance_excel_id
LEFT JOIN tbl_discounts_details DDT ON RGD.rec_gene_id = DDT.recipt_general_id
LEFT JOIN tbl_branches B ON B.branch_id = RGD.policy_closed_branch
WHERE IEX.region_id =2
GROUP BY B.branch_id)k ON k.region_id=E.region_id
LEFT JOIN (
SELECT ex.region_id, B.branch_id AS branches, count( F.`fse_id` ) AS telecallers
FROM tbl_branches B
LEFT JOIN tbl_team_leader L ON B.branch_id = L.leader_branch_id
LEFT JOIN tbl_fse F ON L.leader_id = F.leader_id
JOIN (
SELECT region_id
FROM tbl_insurance_excel
WHERE `region_id` =2
GROUP BY region_id
) AS ex ON B.region_id = ex.region_id
WHERE F.fse_category = 'Telecaller'
GROUP BY B.branch_id
) TCLRS ON TCLRS .region_id=E.region_id
LEFT JOIN (
SELECT ex.region_id, B.branch_id AS branches, count( F.`fse_id` ) AS fses
FROM tbl_branches B
LEFT JOIN tbl_team_leader L ON B.branch_id = L.leader_branch_id
LEFT JOIN tbl_fse F ON L.leader_id = F.leader_id
JOIN (
SELECT region_id
FROM tbl_insurance_excel
WHERE `region_id` =2
GROUP BY region_id
) AS ex ON B.region_id = ex.region_id
WHERE F.fse_category = 'Fse'
GROUP BY B.branch_id
) FSE ON FSE.region_id=E.region_id
WHERE E.region_id=2 GROUP BY k.branches
Notice you were doing a join after the other, and combining results that should be unique in your query. You'd joined the data from the query you named k, and then joined the result with the query you named BAL, that, except by the column balance, had the same entries, and so the branch_id's were being duplicated.
You had, in a quick:
k.branch_id LEFT JOIN BAL.branch_id
which caused your rows to be duplicated, with different balance values.
The result obtained with the query posted is:
REGION_ID STATUS0 STATUS1 DISCOUNT BRANCHES BRANCH_NAMES BALANCE TELECALLERS FSES
2 (null) 4 400 30 KOTTAKKAL 341 3 3
2 (null) 4 800 31 KALPETTA 394 3 3
Regards!
Try This ::
IN your query just append the following part :
GROUP BY branch_names
OR you can get the DISTINCT in your SELECT part as :
Select DISTINCT(branch_names) from....
The final query will be ::
SELECT E.`region_id`,a0.status0,a1.status1,k.discount,k.branches
,k.branch_names,BAL.balance,TCLRS.telecallers,FSE.fses
FROM tbl_insurance_excel E
LEFT OUTER JOIN (Select E2.region_id, count(`id`) as status1
from tbl_insurance_excel E2 Left Join tbl_recipt_general_details on id=insurance_excel_id
JOIN tbl_branches on policy_closed_branch= branch_id
Where E2.`row_status` =1 AND E2.canceled_status='no' and E2.region_id=2 Group by region_id) a1 ON a1.region_id=E.region_id
LEFT OUTER JOIN (Select E2.region_id, count(`id`) as status0
from tbl_insurance_excel E2 Left Join tbl_recipt_general_details on id=insurance_excel_id
JOIN tbl_branches on policy_closed_branch= branch_id
Where E2.`row_status` =0 AND E2.canceled_status='no' and E2.region_id=2 Group by region_id) a0 ON a0.region_id=E.region_id
LEFT JOIN (
SELECT IEX.region_id,B.branch_name as branch_names,B.branch_id as branches, sum( DDT.discounts_amount ) as discount
FROM tbl_insurance_excel IEX
LEFT JOIN tbl_recipt_general_details RGD ON IEX.id = RGD.insurance_excel_id
LEFT JOIN tbl_discounts_details DDT ON RGD.rec_gene_id = DDT.recipt_general_id
LEFT JOIN tbl_branches B ON B.branch_id = RGD.policy_closed_branch
WHERE IEX.region_id =2
GROUP BY B.branch_id)k on k.region_id=E.region_id
LEFT JOIN (
SELECT IEX.region_id,B.branch_id as branches, sum( RGD.`recipt_bal_amount` ) AS balance
FROM tbl_insurance_excel IEX
LEFT JOIN tbl_recipt_general_details RGD ON IEX.id = RGD.insurance_excel_id
LEFT JOIN tbl_branches B ON B.branch_id = RGD.policy_closed_branch
WHERE IEX.region_id =2
GROUP BY B.branch_id)BAL ON BAL.region_id=E.region_id
LEFT JOIN (
SELECT ex.region_id, B.branch_id AS branches, count( F.`fse_id` ) AS telecallers
FROM tbl_branches B
LEFT JOIN tbl_team_leader L ON B.branch_id = L.leader_branch_id
LEFT JOIN tbl_fse F ON L.leader_id = F.leader_id
JOIN (
SELECT region_id
FROM tbl_insurance_excel
WHERE `region_id` =2
GROUP BY region_id
) AS ex ON B.region_id = ex.region_id
WHERE F.fse_category = 'Telecaller'
GROUP BY B.branch_id
) TCLRS ON TCLRS .region_id=E.region_id
LEFT JOIN (
SELECT ex.region_id, B.branch_id AS branches, count( F.`fse_id` ) AS fses
FROM tbl_branches B
LEFT JOIN tbl_team_leader L ON B.branch_id = L.leader_branch_id
LEFT JOIN tbl_fse F ON L.leader_id = F.leader_id
JOIN (
SELECT region_id
FROM tbl_insurance_excel
WHERE `region_id` =2
GROUP BY region_id
) AS ex ON B.region_id = ex.region_id
WHERE F.fse_category = 'Fse'
GROUP BY B.branch_id
) FSE ON FSE.region_id=E.region_id
where E.region_id=2 group by k.branches
did u try to wrap your query with another select and group it by BRANCH_NAMES
SELECT * FROM
(
<< your query goes here>>
) o
GROUP BY o.BRANCH_NAMES
But in case u put your results together like this, you will defnitely loose data in balance column.

mysql filter by result of sub query

i have this Query :
SELECT a.*, a.id AS id_player, (SELECT COUNT(id) FROM `vd7qw_footsal_goals` WHERE a.id = id_player AND g.id = id_group) AS goals,
team.* FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team ON team.id= a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog ON tog.id_team = team.id 4
LEFT JOIN vd7qw_footsal_groups AS g ON g.id = tog.id_group
WHERE g.id IN (SELECT id_group from `vd7qw_footsal_groupofleague` WHERE id_league = 2)
AND (a.state IN (1)) AND goals > 0 ORDER BY goals DESC
and i want to filter its resaults by players that have goals
the above query have error in this part goals > 0 i don't know how to do that can any1 help me ?
Try this:
SELECT * FROM
(SELECT a.*, a.id AS id_player, (SELECT COUNT(id) FROM `vd7qw_footsal_goals` WHERE a.id = id_player AND g.id = id_group) AS goals,
team.* FROM `vd7qw_footsal_players` AS a
LEFT JOIN vd7qw_footsal_teams AS team ON team.id= a.id_team
LEFT JOIN vd7qw_footsal_teamofgroup AS tog ON tog.id_team = team.id 4
LEFT JOIN vd7qw_footsal_groups AS g ON g.id = tog.id_group
WHERE g.id IN (SELECT id_group FROM `vd7qw_footsal_groupofleague` WHERE id_league = 2)
AND (a.state IN (1))) AS A WHERE goals > 0 ORDER BY goals DESC