2 SELECT in a query with ORDER BY - mysql

I need to create a MYSQL query that will return the following:
excel
this is my query
SELECT t1.fecha_salida,
t1.agencia,
t2.fecha_salida,
t2.directa
FROM (SELECT fecha_salida, COUNT(*) AS agencia
FROM ventas
WHERE ventas.eliminado = 0 AND ventas.cliente_id !=2
GROUP BY fecha_salida) AS t1,
(SELECT fecha_salida, COUNT(*) AS directa
FROM ventas
WHERE ventas.eliminado = 0 AND ventas.cliente_id =2
GROUP BY fecha_salida) AS t2
GROUP BY t1.fecha_salida
my table is:
|------ |Columna|Tipo|Nulo|Predeterminado |------
|//**venta_id**//|int(11)|No| |usuario_id|int(11)|No|
|tour_id|int(11)|No| |cliente_id|int(11)|No| |vehiculo_id|int(11)|No|
|cashflow_id|int(11)|No| |total_compra|int(6)|No|
|total_pagado|int(6)|No| |total_iva|int(6)|No|
|total_comision|int(11)|No| |a_pagar|int(11)|No|
|fecha_venta|datetime|No| |fecha_salida|date|No|
|concretada|tinyint(1)|No| |pasajeros|int(3)|No|
|nombre|varchar(500)|Sí|NULL |direccion|varchar(500)|Sí|NULL
|observaciones|varchar(500)|Sí|NULL |forma_pago|tinyint(2)|No|
|eliminado|tinyint(1)|No|
Can you help me

You can use UNION to combine two queries that have same structure , also you should select from combined result and then order them
SELECT * FROM (
SELECT fecha_salida, COUNT(*) AS agencia
FROM ventas
WHERE `fecha_venta` between '2012-03-11 00:00:00' and '2019-08-30 23:59:00'
and ventas.eliminado = 0
AND ventas.cliente_id = 2
GROUP BY fecha_salida
UNION
SELECT fecha_salida, COUNT(*) AS agencia
FROM ventas
WHERE `fecha_venta` between '2012-03-11 00:00:00' and '2019-08-30 23:59:00'
and ventas.eliminado = 0
AND ventas.cliente_id != 2
GROUP BY fecha_salida
) RESULT
ORDER BY agencia

Related

Group by date and take the last one

This is my table :
What I'm trying to do, is to take the last disponibility of a user, by caserne. Example, I should have this result :
id id_user id_caserne id_dispo created_at
31 21 12 1 2019-10-24 01:21:46
33 21 13 1 2019-10-23 20:17:21
I've tried this sql, but it does not seems to work all the times :
SELECT * FROM
( SELECT id, id_dispo, id_user, id_caserne, MAX(created_at)
FROM disponibilites GROUP BY id_user, id_caserne, id_dispo
ORDER BY created_at desc ) AS sub
GROUP BY id_user, id_caserne
What am I doing wrong ?
I would simply use filtering in the where clause using a correlated subquery:
select d.*
from disponibilites d
where d.created_at = (select max(d2.created_at)
from disponibilites d2
where d2.id_user = d.id_user
);
EDIT:
Based on your comments:
select d.*
from disponibilites d
where d.created_at = (select max(d2.created_at)
from disponibilites d2
where d2.id_user = d.id_user and
d2.id_caserne = d.id_caserne
where date(d2.created_at) = date(d.created_at)
);
You can use a correlated subquery, as demonstrated by Gordon Linoff, or a window function if your RDBMS supports it:
select * from (
select
t.*,
rank() over(partition by id_caserne, id_user order by created_at desc) rn
from disponibilites t
) x
where rn = 1
Another option is to use a correlated subquery without aggregation, only with a sort and limit:
select *
from mytable t
where created_at = (
select created_at
from mytable t1
where t1.id_user = t.id_user and t1.id_caserne = t.id_caserne
order by created_at desc
limit 1
)
With an index on (id_user, id_caserne, created_at), this should be a very efficient option.
you can join your max(created_date) to your original table
select t1.* from disponibilites t1
inner join
(select max(created_at), id_caserne, id
from disponibilites
group by id_caserne, id) t2
on t2.id = t1.id

How can I select related items within the same table in one SQL query

I have a table looking like this:
id | date | related_id
1 2018-01-01
2 2018-01-01
3 2018-01-02
4 2018-01-05 2
5 2018-01-06
A query SELECT * FROM table WHERE date='2018-01-01' should produce the following result:
id | date | related_id
1 2018-01-01
2 2018-01-01
4 2018-01-05 2
How can I achieve that in one MySql query?
If you have only one "layer", you can do this:
SELECT t.*
FROM theTable AS t
LEFT JOIN theTable AS rt ON t.related_id = rt.id
WHERE t.`date` = searchValue OR rt.`date` = searchValue
;
If there are an indefinite number of layers, and you have MySQL 8.0, you can use a CTE:
WITH RECURSIVE myCte AS (
SELECT * FROM theTable WHERE `date` = searchValue
UNION
SELECT t.*
FROM theTable AS t
INNER JOIN myCTE ON t.related_id = myCTE.id
)
SELECT * FROM myCTE;
Disclaimer: I am more familiar with MS-SQL CTE's, so there could be some problems with that latter option.
Extend your WHERE condition to the related_id's date:
SELECT * FROM table t
WHERE
t.date = '2018-01-01'
OR
(SELECT date FROM table WHERE id = t.related_id) = '2018-01-01'
or with a self join:
SELECT t.*
FROM table t LEFT JOIN table tt
ON tt.id = t.related_id
WHERE
t.date = '2018-01-01'
OR
tt.date = '2018-01-01'
or with EXISTS:
SELECT t.*
FROM table t
WHERE
t.date = '2018-01-01'
OR
EXISTS (
SELECT 1 FROM table
WHERE id = t.related_id AND date = '2018-01-01'
)
You can use EXISTS :
SELECT t.*
FROM table t
WHERE t.date = '2018-01-01' OR
EXISTS (SELECT 1 FROM table t1 WHERE t.related_id = t1.id);
You can simply do this:
SELECT table.* FROM table LEFT JOIN table related
ON table.related_id = related.id
WHERE
table.date = '2018-01-01'
OR related.date = '2018-01-01';
this will work with the date function:
SELECT * FROM table WHERE date=DATE('2018-01-01');
or
SELECT * FROM table WHERE date=STR_TO_DATE(DATE, '%d/%m/%Y')

SQL where exists

I am trying to get the total amount spent on transactions with a specific product sold during the period below.
SELECT
i.Customer,
SUM(i.GrandTotal)
FROM
transaction i
WHERE EXISTS
(SELECT
1
FROM
transactionline il
INNER JOIN product p
ON p.ProductId = il.ProductId
WHERE i.InvoiceDate >= '2016-09-01 00:00:00'
AND i.InvoiceDate <= '2017-08-31 23:59:59'
AND p.TableProductType = 25)
GROUP BY i.Customer;
My problem is that this query has a result the total amount spent during that period and not only transactions with that product involved
I started of with something like this :
SELECT
i.Customer,
SUM(i.GrandTotal)
FROM
transaction i,transactionline il , product p
WHERE i.InvoiceDate >= '2016-09-01 00:00:00'
AND i.InvoiceDate <= '2017-08-31 23:59:59'
AND p.TableProductType = 25);
But this also took much longer and the final result was wrong (cause of the multiplication caused by the join between transaction and transaction line)
few ways, all solutions using the with following as its data source directly before query, but substitute with your table name
with dat
as
(
select 1 tranid,'N' Tableproducttype,9.00 GrandTotal union all
select 1,'N',11.12 union all
select 1,'N',14.23 union all
select 1,'25',8.88 union all
select 1,'N',7.77 union all
select 1,'Y',6.66 union all
select 2,'N',3.21 union all
select 2,'N',19.13 union all
select 2,'Y',1.23 union all
select 3,'Y',4.31 union all
select 4,'Y',15.43 union all
select 4,'Y',15.12 union all
select 5,'N',14.32)
1.) works using an IN
select tranid,sum(GrandTotal) GrandTotal
from dat
where tranid in (select tranid from dat where TableProductType = '25')
group by tranid
2.) using an exists
select tranid,sum(GrandTotal) GrandTotal
from dat
where exists (select 'x' from dat dat_inner
where dat_inner.TableProductType = '25'
and dat_inner.tranid = dat.tranid)
group by tranid
3.) using having, but could be slow
select tranid,sum(GrandTotal) GrandTotal
from dat
group by tranid
having sum(case when TableProductType = '25' then 1 else 0 end)>0 /* at least one product of type 25 */

Why is MySQL cumulative sum producing wrong results

I need to find the cumulative sum for the following data:
Following query:
SELECT created, COUNT( * )
FROM `transactions`
GROUP BY created
Gives me:
created COUNT( * )
2015-8-09 1
2015-8-15 1
2015-8-16 2
2015-8-17 1
2015-8-23 1
I tried to do the cumulative sum like:
SELECT t1.created, COUNT( * ) , SUM( t2.totalcount ) AS sum
FROM transactions t1
INNER JOIN (
SELECT id, created c, COUNT( * ) AS totalcount
FROM transactions
GROUP BY created
ORDER BY created
)t2 ON t1.id >= t2.id
GROUP BY t1.created
ORDER BY t1.created
but the results it gives arent as expected:
created COUNT( * ) sum
2015-8-09 5 6
2015-8-15 3 4
2015-8-16 6 8
2015-8-17 1 1
2015-8-23 4 5
How do i produce the following result:
created COUNT( * ) sum
2015-8-09 1 1
2015-8-15 1 2
2015-8-16 2 4
2015-8-17 1 5
2015-8-23 1 6
select tmp.*, #sum := #sum + cnt as cum_sum
from
(
SELECT created, COUNT( * ) as cnt
FROM `transactions`
GROUP BY created
ORDER BY created
) tmp
cross join (select #sum := 0) s
Your inner query is selecting id without grouping on it. Let's rework it in terms of the date.
SELECT t1.created, COUNT( * ) AS daycount, SUM( t2.totalcount ) AS sum
FROM transactions t1
INNER JOIN ( SELECT created, COUNT( * ) AS totalcount
FROM transactions
GROUP BY created
) t2 ON t1.created >= t2.created
GROUP BY t1.created
ORDER BY t1.created;
Or you might want to put the totalcount inline:
SELECT t1.created, COUNT(*) AS daycount
, ( SELECT COUNT(*) FROM transactions t2
WHERE t2.created <= t1.created ) AS totalcount
FROM transactions t1
GROUP BY created
ORDER BY CREATED;

Select the most recent row from a log table using timestamp

I have a table for logging a Facebook application user actions. I want to get the latest row that is not older then 9 minutes for a specific action ID. The table has a lot of columns of other statistical information, so I will show only 2 of the rows that represent the problem:
timestamp facebookID producerID eventID actionID numOfTickets
2012-05-28 13:16:38 100003286974944 9 1741 cpf 2
2012-05-28 13:16:13 100003286974944 9 1741 cpf 4
What I want to do is getting the latest row where actionID = 'cpf'.
What I've tried is:
SELECT CONCAT_WS(' ', y.firstName, y.lastName) as fullName, x.facebookID, x.numOfTickets, MAX(x.timestamp)
FROM E4S_ANALYTICS.e4s_analytic_data x INNER JOIN E4S_FB.e4s_user_details y ON x.facebookID = y.facebookID
WHERE (x.actionID = 'CPF' AND x.numOfTickets > 0 AND x.producerID = 9 AND TIMEDIFF(NOW() , x.timestamp) < '00:09:00'
AND x.facebookID IN (SELECT facebookID FROM E4S_FB.e4s_session_data WHERE
TIMEDIFF(NOW() , sessionStart) < '00:09:00' ))
The result of the query is:
facebookID numOfTickets MAX(x.timestamp)
100003286974944 4 2012-05-28 13:16:38
The timestamp returned is correct but the numOfTickets is 4 instead of 2.
For note, the inner query:
SELECT facebookID FROM E4S_FB.e4s_session_data
WHERE TIMEDIFF(NOW() , sessionStart) < '00:09:00' ))
Is used to see who is still logged in to the application.
SELECT CONCAT_WS(' ', y.firstName, y.lastName) AS fullName,
x.facebookID,
x.numOfTickets,
x.timestamp
FROM (
SELECT *
FROM E4S_ANALYTICS.e4s_analytic_data
WHERE actionID = 'cpf'
AND numOfTickets > 0
AND producerID = 9
AND TIMEDIFF(NOW() , timestamp) < '00:09:00'
AND (facebookID, timestamp) IN (
SELECT facebookID, MAX(timestamp)
FROM E4S_ANALYTICS.e4s_analytic_data
WHERE actionID = 'cpf'
AND numOfTickets > 0
AND producerID = 9
AND TIMEDIFF(NOW() , timestamp) < '00:09:00'
AND facebookID IN (
SELECT facebookID
FROM E4S_FB.e4s_session_data
WHERE TIMEDIFF(NOW() , sessionStart) < '00:09:00'
)
GROUP BY facebookID
)
) AS x
INNER JOIN E4S_FB.e4s_user_details AS y USING (facebookID)
you can use order by timestamp desc to order the column according to latest first and then select the first row.
or try using max.
Have you tried not using MAX()?
Assuming you've checked JOIN and SUBQUERY results.
SELECT CONCAT_WS(' ', y.firstName, y.lastName) as fullName, x.facebookID, x.numOfTickets, MAX(x.timestamp)
FROM E4S_ANALYTICS.e4s_analytic_data x
INNER JOIN E4S_FB.e4s_user_details y ON x.facebookID = y.facebookID
GROUP BY x.facebookID
WHERE (x.actionID = 'CPF' AND x.numOfTickets > 0 AND x.producerID = 9 AND TIMEDIFF(NOW() , x.timestamp) < '00:09:00'
AND x.facebookID IN
(SELECT facebookID FROM E4S_FB.e4s_session_data
WHERE TIMEDIFF(NOW() , sessionStart) < '00:09:00' ))
ORDER BY x.timestamp DESC;