Remove duplicates from result using MySQL and PHP - php

I have a query given below
SELECT A.order_no, A.order_date,
COUNT(B.reaction_no) as tot_reaction_no,
SUM(CASE
WHEN (B.purification != '') THEN 1
ELSE 0
END) as tot_purification
FROM order_header A
LEFT JOIN order_reactions B ON A.order_no = B.order_no
WHERE A.order_date BETWEEN '2015-10-01 00:00:00' AND '2016-09-01 00:00:00'
AND A.order_no = '23746'
GROUP BY A.order_no
this will results as shown in the picture. But the result is wrong because some of the entries are duplicates. So I have to remove the duplicate and print the count. Count required is the count of "column" from the table 1.

I think you need to leave out the A.order_date in your select or you should add it to the group by clause. That gives you a different result though.
You may also use a subquery in your select clause:
SELECT A.order_no, A.order_date,
COUNT(B.reaction_no) as tot_reaction_no,
(SELECT count(*) FROM order_reactions as or WHERE or.order_no=A.order_no AND purification!='') as tot_purification,
(SELECT count(*) FROM order_reactions as or2 WHERE or.order_no=A.order_no) as tot_reaction_no
FROM order_header A
WHERE A.order_date BETWEEN '2015-10-01 00:00:00' AND '2016-09-01 00:00:00'
AND A.order_no = '23746'
This is just from the top of my head, since your screenshots are not showing the full tables I'm not sure this is 100% right, but it might point you in the right direction.

I would propose the query
SELECT COUNT(DISTINCT clone_name) AS tot_purification, COUNT(*) AS tot_reaction_no FROM Table2 WHERE `purification`='Column' AND `order_no`=23746;
Please excuse errors in quotation, MySQL is very confusing when it comes to quotation imo.
EDIT:
Added AS tot_purification
I'm not sure what you are expecting as tot_reaction_no, so I just counted all rows where Order and purification match as described in my WHERE clause.

Its because you are grouping only on A.order_no, make following changes in the query and try again:
Replace the line:
GROUP BY A.order_no;
to
GROUP BY A.order_no, A.clone_name;

Related

PHP - SQL optimization min/max too slow

I'm having some problems with a query that finds the next ID of an orders with certain filters on it - Like it should be from a specific city, etc.
Currently it's used for a function, where it'll either spit out the previous or the next ID based on the current order. So it can either be min(id) or max(id), where max(id) is obviously faster, since it has to go through less rows.
The query is working just fine, but it's rather slow, since it's going through 123953 rows to find the ID. Is there any way I could optimize this?
Function example:
SELECT $minmax(orders.orders_id) AS new_id FROM orders LEFT JOIN orders_status ON orders.orders_status = orders_status.orders_status_id $where_join WHERE orders_status.language_id = '$languages_id' AND orders.orders_date_finished != '1900-01-01 00:00:00' AND orders.orders_id $largersmaller $ordersid $where;
Live example
SELECT min(orders.orders_id)
FROM orders
LEFT JOIN orders_status ON orders.orders_status = orders_status.orders_status_id
WHERE orders_status.language_id = '4'
AND orders.orders_date_finished != '1900-01-01 00:00:00'
AND orders.orders_id < 4868771
LIMIT 1
so concluding:
SELECT orders.orders_id
FROM orders
JOIN orders_status ON orders.orders_status = orders_status.orders_status_id
WHERE orders_status.language_id = '4'
AND orders.orders_date_finished != '1900-01-01 00:00:00'
AND orders.orders_id < 4868771
ORDER BY orders.orders_id ASC
LIMIT 1
Extra:
to get the MAX value, use DESC where ASC is now.
And looking at your question: be sure to escape the values like $language_id etcetera. I suppose they could come from some html form?
(or use prepared statements)

Get data if insert are in the same second

I have this table :
id idm date_play
1 5 2017-08-23 12:12:12
2 5 2017-08-23 12:12:12
3 6 2017-08-23 12:14:13
I want to identify if user has more then one insert in the same second. In the case describe I want to get the user id that is 5.
I tried like this :
SELECT `idm`, MAX(`s`) `conseq` FROM
(
SELECT
#s := IF(#u = `idm` AND (UNIX_TIMESTAMP(`date_play`) - #pt) BETWEEN 1 AND 100000, #s + 1, 0) s,
#u := `idm` `idm`,
#pt := UNIX_TIMESTAMP(`date_play`) pt
FROM table
WHERE date_play >= '2017-08-23 00:00:00'
AND date_play <= '2017-08-23 23:59:59'
ORDER BY `date_play`
) AS t
GROUP BY `idm`
Can you help me please ? Thx in advance and sorry for my english.
Assuming your dates are accurate down to the second level, you can do this with a single aggregation:
select idm
from t
group by idm
having count(*) > count(distinct date_play);
If date_play has fractional seconds, then you would need to remove those (say by converting to a string).
If you want the play dates where there are duplicates:
select idm, date_play
from t
group by idm, date_play
having count(*) >= 2;
Or, for just the idms, you could use select distinct with group by:
select distinct idm
from t
group by idm, date_play
having count(*) >= 2;
(I only mention this because this is the only type of problem that I know of where using select distinct with group by makes sense.)
If you want all the rows that are duplicated, I would go for exists instead:
select t.*
from t
where exists (select 1
from t t2
where t2.idm = t.idm and t2.date_play = t.date_play and
t2.id <> t.id
);
This should have reasonable performance with an index on (idm, date_play, id).
If your table is called mytable, the following should work:
SELECT t.`idm`
FROM mytable t INNER JOIN mytable t2
ON t.`idm`=t2.`idm` AND t.`date_play`=t2.`date_play` AND t.`id`!=t2.`id`
GROUP BY t.`idm`
Basically we join the table with itself, pairing records that have the same idm and date_play, but not the same id. This will have the effect of matching up any two records with the same user and datetime. We then group results by user so you don't get the same user id listed multiple times.
Edit:
Gordon Linoff and tadman's suggestions led me to this probably much more efficient query (credit to them)
SELECT t.`idm`
FROM mytable t
GROUP BY t.`date_play`
HAVING COUNT(t.`id`)>1

to accelerate mysql query

I have this query in MySQL. This query is taking too long to run, and I know the problem is the selectors (coalesce ((SELECT ...), I do not know how to speed up a query, via join.
I am hoping some of you SQL gurus will be able to help me.
SELECT
COALESCE(
(SELECT CONCAT(d.PRIJEVOZNIK, ' ', d.VOZAC_TRANSFER)
FROM dokum_zag as d
where d.SIFKNJ='NP' and
d.ID_VEZA=dokum_zag.ID and
d.korisnicko_ime=dokum_zag.korisnicko_ime
),'') as PRIJEVOZNIK,
(RELACIJA_TRANS_VOZ_TRANS) as RELACIJA_TRANS_VOZ,
(PRIJEVOZNIK_POVRATNI_TRANS) as PRIJEVOZNIK_POVRATNI,
(VAUC_KNJIZENO_TRANS) as VAUC_KNJIZENO,
ID_NALOGA,
ID_NALOGA_POV,
ID_VAUCHER,
DOLAZAK, VRIJ_TRANSFER,ODLAZAK,VRIJEME_LETA_POVRAT ,BRDOK, NOSITELJ_REZ, RELACIJA_TRANS, VOZILO_NAZIV, BROJ_NALOGA,BROJ_NAL_POV,BROJ_VAUCHER,BROJ_SOBE,VALIZN,PAX, MPIZN,ID
FROM
dokum_zag
WHERE
korisnicko_ime = '10' and
((DOLAZAK='2015-07-30') or (ODLAZAK='2015-07-30')) and
STORNO <> 'DA' and
SIFKNJ = 'TR' and
((YEAR(DOLAZAK)= '2015') or (YEAR(ODLAZAK)= '2015'))
order by
(CASE WHEN DOLAZAK < '2015-07-30' THEN ODLAZAK ELSE DOLAZAK END) ,
(CASE WHEN DOLAZAK < '2015-07-30' THEN VRIJEME_LETA_POVRAT ELSE VRIJ_TRANSFER END), ID
Without a DB structure, and a description of what you want to extract it's a bit hard to help you.
From a logical point of view, somethings are redundant, for example
((DOLAZAK='2015-07-30') or (ODLAZAK='2015-07-30')) and
...
((YEAR(DOLAZAK)= '2015') or (YEAR(ODLAZAK)= '2015'))
The year part isn't necessary since the year is specified on the first two.
Another thing that might be making the server nuts, is that weird order by clause, since it changes from record to record (test this setting it fixed on a field).
You can also check if your indexes are properly set for all the fields on the external where clause, and those which are not numeric, are not varchars (for example SIFKNJ and STORNO should be char(2) ).
The coalesce part can be solved via an outer join, so it doesn't get calculated on each row. But that depends on what and how you want to extract from the database... (since that subquery has it's own fields on the where section... weird)
Hope this somehow helps
INDEX(korisnicko_ime, SIFKNJ)
(in either order) may help
Turning the correlated subquery into a JOIN may help.
((DOLAZAK='2015-07-30') or (ODLAZAK='2015-07-30')) and
((YEAR(DOLAZAK)= '2015') or (YEAR(ODLAZAK)= '2015'))
is a bit weird. This might help:
( SELECT ...
AND DOLAZAK ='2015-07-30' AND ODLAZAK >= '2015-01-01'
AND ODLAZAK < '2015-01-01' + INTERVAL 1 YEAR
) UNION DISTINCT
( SELECT ...
AND ODLAZAK ='2015-07-30' AND DOLAZAK >= '2015-01-01'
AND DOLAZAK < '2015-01-01' + INTERVAL 1 YEAR
) ORDER BY ...
To help that reformulation, add 2 composite indexes:
INDEX(korisnicko_ime, SIFKNJ, DOLAZAK, ODLAZAK)
INDEX(korisnicko_ime, SIFKNJ, ODLAZAK, DOLAZAK)

how to select max and min

I have script query select like this. I want to search value max and min 'jumlah' from query select.
SELECT
"B"."company" AS "B__company",
"User"."company" AS "User__company",
"Transaction"."create_date" AS "Transaction__create_date",
extract(day from "Transaction"."create_date"),
sum(cast("PLNPostpaid"."jumlahrek" as integer)) as jumlah,
sum("Transaction"."price_buy") as jumbuy,
sum(("Transaction"."price_sell")-("Transaction"."price_buy")) as admin
FROM "public"."transactions" AS "Transaction"
LEFT OUTER JOIN "public"."users" AS "User" ON ("User"."id" = "Transaction"."user_id")
FULL OUTER JOIN "public"."users" AS "B" ON ("B"."id" = "User"."bank")
LEFT JOIN "public"."inboxes" AS "Inbox" ON ("Inbox"."id" = "Transaction"."inbox_id")
LEFT JOIN "public"."pln_postpaids" AS "PLNPostpaid" ON ("Inbox"."id" = "PLNPostpaid"."inbox_id")
WHERE "Transaction"."create_date" >= '01-May-2015 00:00:00' AND "Transaction"."create_date" <= '31-May-2015 23:59:59'
AND "Transaction"."product_id"=100
GROUP BY extract(day from "Transaction"."create_date"), "Transaction"."create_date", "B"."company", "User"."company"
and I want to implement to php. Can anyone help me?
I think you need a subquery to select min and max.
For example,
WITH all_data AS (
-- YOUR INITIAL REQUEST GOES HERE
)
SELECT MIN (jumlah) as min_jumlah, MAX(jumlah) as max_jumlah
FROM all_data
It's unclear what syntax your code represents. If you compile the query from php, then you shouldn't use quotes like this. The whole string containing the query should be double quoted, but you don't need these double quotes inside.

What is the error in my query?

in below query it returns 12 record while query in from clause (as t) returns 18 record, can anyone help what is the issue in this query?
SELECT count(abc.id) as total_this_month,t.*
FROM email_details abc
JOIN
(SELECT count(email_details.id) as total_emails,MAX(`email_details`.email_date) as email_date1, `email_details`.* FROM (`cld_users` join email_details on email_details.fk_user_id = cld_users.id) GROUP BY `email_details`.`email_title` ORDER BY `email_details`.`email_date` DESC) as t
ON abc.email_title = t.email_title
where (MONTH(abc.email_date)=MONTH(NOW()) AND YEAR(abc.email_date)=YEAR(NOW()))
group by t.email_title
ORDER BY t.`email_date` DESC
In your query, you specify
where (MONTH(abc.email_date)=MONTH(NOW()) AND YEAR(abc.email_date)=YEAR(NOW()))
But in the subquery (the one returning 18 results), you have 6 emails with a month that is not december 2014. There's no way that those emails can be returned by a query that explicitly excludes them.
You want those emails as well so you get 18 results ? Remove the WHERE clause excluding them:
SELECT Count(abc.id) AS total_this_month,
t.*
FROM email_details abc
JOIN (SELECT Count(email_details.id) AS total_emails,
Max(`email_details`.email_date) AS email_date1,
`email_details`.*
FROM (`cld_users`
JOIN email_details
ON email_details.fk_user_id = cld_users.id)
GROUP BY `email_details`.`email_title`
ORDER BY `email_details`.`email_date` DESC) AS t
ON abc.email_title = t.email_title
GROUP BY t.email_title
ORDER BY t.`email_date` DESC
Starting from there, if you want to count the emails from the current month, simply replace:
SELECT Count(abc.id) AS total_this_month,
with
SELECT SUM(CASE WHEN MONTH(abc.email_date)=MONTH(NOW()) AND YEAR(abc.email_date)=YEAR(NOW()) THEN 1 ELSE 0 END) AS total_this_month,

Categories