combining rows in same table sql - mysql

sample_data
id_type,seq_no,acct_name,_acct#,address
12345,67,jiimm,,167 s.40th st
12345,67,jiimm joe the 3rd,,167 s.40th st
12345,67,jiimm
12345,67,,0981_1,po box 1234
12345,80,Lee,,1234 street ave
12345,80,Lee
12345,80,,588_1,109 road st
CODE
SELECT `ID`_type,
seq_no,
MAX(`acct_name`) AS acct_name,
MAX(`acct_#`) AS acct_#,
address
FROM `test_table`
GROUP BY `ID`_type,
seq_no;
I want to merge rows based on by id_type and seq_no. I am using max to merge the rows but I am overwriting any exisiting addresses and acct_names due to the MAX acct#.
my results
id_type,seq_no.,acct_name,_acct#,address
12345,67,jiimm joe the 3rd,0981_1,167 s.40th st
12345,80,Lee,588_1,109 road st
Losing po box 1234 for 67-
Losing 1234 street ave for 80, losing jiimm-
desired results
12345,80,Lee,588_1,109 road st
12345,80,Lee,588_1,1234 street ave
12345,67,jiimm,0981_1,167 s.40th st
12345,67,jiimm,0981_1,po box 1234
12345,67,jiimm joe the 3rd,0981_1,167 s.40th st

This gives you what you're looking for, but read my comment / question underneath your question above. There is an ambiguous "pick one row from many" situation that needs clarification. In that ambiguous situation, you imply that rules call for delivering the minimum non-blank account name, which this code does, but you can see how it requires treating the account name one way, and treating the acct (#) and address a different way. I think you're headed for an application that delivers results based on hard to remember rules. Funky rules like that end up getting reported as defects, even if you publish said processing rules. Hence, you may want to enhance the process upstream that captures this data to deliver more disciplined data.
SQLFIDDLE link - In short the inner query populates missing values, then the outer result set delivers the distinct rows. I tested this with blank values not null. I did make a quick effort to add the code to handle nulls, but I didn't test it using nulls, so I suggest testing it as such if that is what production will use.
select distinct * from (
select d.id_type, d.seq_no
,coalesce( nullif( acct_name, ''), min_acct_name ) as merged_acct_name
,coalesce( nullif( acct, ''), max_acct ) as merged_acct
,coalesce( nullif( address, ''), max_address ) as merged_address
from test_table d
left join ( select id_type, seq_no
,max( acct ) as max_acct
,max( address ) as max_address
from test_table
group by id_type, seq_no
) as max_
on max_.id_type = d.id_type and max_.seq_no = d.seq_no
and ( coalesce( d.acct,'' ) = ''
or coalesce( d.address,'' ) = '' )
left join ( select id_type, seq_no
,min( acct_name ) as min_acct_name
from test_table
where coalesce( acct_name, '' ) <> ''
group by id_type, seq_no
) as min_
on min_.id_type = d.id_type and min_.seq_no = d.seq_no
and coalesce( d.acct_name,'' ) = ''
) as t
order by id_type, seq_no desc, merged_acct_name, merged_acct, merged_address

Try this:
select distinct t1.id_type, t1.seq_no
,coalesce( t1.acct_name, t2.acct_name ) as merged_acct_name
,coalesce( t1.acct, t2.acct ) as merged_acct
,coalesce( t1.address, t2.address ) as merged_address
from test_table t1
left join test_table t2
on t1.id_type = t2.id_type
and t1.seq_no = t2.seq_no
where concat(coalesce( t1.acct_name, t2.acct_name )
,coalesce( t1.acct, t2.acct )
,coalesce( t1.address, t2.address ) ) is not null
order by t1.id_type, t1.seq_no;
Or:
select distinct t1.id_type, t1.seq_no
,coalesce( t1.acct_name, t2.acct_name ) as merged_acct_name
,coalesce( t1.acct, t3.acct ) as merged_acct
,coalesce( t1.address, t4.address ) as merged_address
from test_table t1
left join test_table t2
on t1.id_type = t2.id_type
and t1.seq_no = t2.seq_no
left join test_table t3
on t1.id_type = t3.id_type
and t1.seq_no = t3.seq_no
left join test_table t4
on t1.id_type = t4.id_type
and t1.seq_no = t4.seq_no
where concat(coalesce( t1.acct_name, t2.acct_name )
,coalesce( t1.acct, t3.acct )
,coalesce( t1.address, t4.address ) ) is not null
order by t1.id_type, t1.seq_no;
SQL Fiddle Demo

SELECT
D1.id_type
, D1.seq_no
, IFNULL(D1.acct_name, (SELECT MIN(acct_name) FROM data D WHERE D.id_type = D1.id_type AND D.seq_no = D1.seq_no)) t
, IFNULL(D1.acct_no, (SELECT MAX(acct_no) FROM data D WHERE D.id_type = D1.id_type AND D.seq_no = D1.seq_no)) s
, D1.address
FROM data D1
WHERE D1.address IS NOT NULL
ORDER BY id_type, seq_no DESC, acct_name
;
returns
| ID_TYPE | SEQ_NO | T | S | ADDRESS |
|---------|--------|-------------------|--------|-----------------|
| 12345 | 80 | Lee | 588_1 | 109 road st |
| 12345 | 80 | Lee | 588_1 | 1234 street ave |
| 12345 | 67 | jiimm | 0981_1 | po box 1234 |
| 12345 | 67 | jiimm | 0981_1 | 167 s.40th st |
| 12345 | 67 | jiimm joe the 3rd | 0981_1 | 167 s.40th st |
Which is consistent with your expected output except for the order of the third and fourth row. However, for larger amounts of data MAX and MIN will become more and more likely to be of limited help.
SQL Fiddle

Related

MySQL script triggers Error #1241

I have the script below, which is supposed to get a price for an array of ID's that has been provided.
But it needs to get 1 price per ID, and the tricky part is, that I want to have the ability to have scheduled price updates.
This mean that it needs to take the price that is <= UTC_TIMESTAMP smaller or equal to the current time.
SELECT
`product_pricing`.`wo_id`,
`product_pricing`.`currency` AS price2_currency,
`product_pricing`.`price` AS price2,
`product_pricing`.`formula_id`,
`product_pricing`.`vat_calculated` AS price2_vat_calculated,
`product_pricing`.`vat_id`,
`product_pricing`.`timestamp_valid`,
`product_price_formulas`.`formula_id`,
`product_price_formulas`.`formula` price2_formula
FROM
`product_pricing`
LEFT JOIN `product_price_formulas`
ON `product_pricing`.`formula_id` = `product_price_formulas`.`formula_id`
WHERE
`product_pricing`.`wo_id` IN (
SELECT
`product_pricing`.`wo_id`,
`product_pricing`.`timestamp_valid`
FROM `product_pricing`
WHERE
`product_pricing`.`wo_id`
IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791')
AND `product_pricing`.`timestamp_valid` <= UTC_TIMESTAMP
ORDER BY `product_pricing`.`timestamp_valid` DESC
)
Is this possible?
Sample data: Current output
——————————————————————————————————————————————————————————————————
| wo_id | price2 | timestamp_valid
——————————————————————————————————————————————————————————————————
| 028791 | 8000 | 2018-03-20 19:55:41
| 028791 | 6000 | 2018-04-01 19:55:41
| 028791 | 4000 | 2018-04-20 19:55:41
| 015724 | 3000 | 2018-04-18 19:55:41
| 015724 | 1500 | 2018-03-01 19:55:41
....
Wanted output:
——————————————————————————————————————————————————————————————————
| wo_id | price2 | timestamp_valid
——————————————————————————————————————————————————————————————————
| 028791 | 6000 | 2018-04-01 19:55:41
| 015724 | 1500 | 2018-03-01 19:55:41
I guess your issue is on the IN clause.
You select two field in IN clause.
EDIT
You need to self join a subquery by wo_id and Max timestamp_valid.
SELECT
`product_pricing`.`wo_id`,
`product_pricing`.`currency` AS price2_currency,
`product_pricing`.`price` AS price2,
`product_pricing`.`formula_id`,
`product_pricing`.`vat_calculated` AS price2_vat_calculated,
`product_pricing`.`vat_id`,
`product_pricing`.`timestamp_valid`,
`product_price_formulas`.`formula_id`,
`product_price_formulas`.`formula` price2_formula
FROM
`product_pricing`
LEFT JOIN `product_price_formulas` ON `product_pricing`.`formula_id` = `product_price_formulas`.`formula_id`
INNER JOIN
(
SELECT
`product_pricing`.`wo_id`,
MAX(`timestamp_valid`) AS MaxDate
FROM `product_pricing`
WHERE
`product_pricing`.`timestamp_valid` <= UTC_TIMESTAMP
GROUP BY
`product_pricing`.`wo_id`
)as temp ON temp.wo_id = `product_pricing`.`wo_id` AND temp.MaxDate = `product_pricing`.`timestamp_valid`
WHERE
`product_pricing`.`wo_id` IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791')
I think you want something like this:
SELECT pp.*, ppf.formula_id, ppf.formula as price2_formula
FROM product_pricing pp LEFT JOIN
product_price_formulas ppf
ON pp.formula_id = ppf.formula_id
WHERE (pp.wo_id, pp.timestamp_valid) IN
(SELECT pp2.wo_id, MAX(pp2.timestamp_valid)
FROM product_pricing pp2
WHERE pp2.wo_id IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791') AND
pp2.timestamp_valid <= UTC_TIMESTAMP
);
The ORDER BY makes no sense in the subquery, so this is my best guess as to what you want.
I left this with your structure of using IN, but I would use a correlated subquery and =:
WHERE pp.timestamp_valid = (SELECT MAX(pp2.timestamp_valid)
FROM product_pricing pp2
WHERE pp2.wo_id = pp.wo_id AND
pp2.timestamp_valid <= UTC_TIMESTAMP
) AND
pp2.wo_id IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791');
You could JOIN product_pricing with a derived result set of the most recent valid_timestamp records.
If we ignore the product_pricing_formula table for now (since you didn't include it in your specimen data and result) that would give.
SELECT
p.`wo_id`,
p.`price` AS price2,
p.`timestamp_valid`
FROM `product_pricing` p
JOIN (SELECT wo_id, MAX(timestamp_valid) AS max_valid_ts
FROM `product_pricing`
WHERE `timestamp_valid` <= UTC_TIMESTAMP
GROUP BY wo_id) d
ON (d.wo_id = p.wo_id AND d.max_valid_ts = p.timestamp_valid)
WHERE p.`wo_id` IN (015724, 028791);
Try it on Sqlfiddle

mysql: difference between values in one column

this board helped me a few times in the past.
My challange: I want to get the difference between the values within one column.
The table looks like this:
id | channel_id | timestamp | value
4515| 7 |1519771680000 | 7777
4518| 8 |1519772160000 | 6666
4520| 7 |1519772340000 | 8888
id: Internal ID from Datasource. In some cases it's ordered, in other cases not. We cannot thrust this order.
channel_id: Different data sources.
timestamp: unix timestamp.
value: measured value.
What I want to do:
Filter (e.g. channel_id = 7).
Calculate the difference between one timestamp and the next one. In this example: 8888-7777
I found an solution on another database but I cannot transfer it to mysql as the windows functions are very limited. Has somebody of you an idea how to get a solution which can be used in select statements?
Thx and KR
Holger
You can get the two rows to compare (ie subtract) by joining the table to itself:
SELECT
a.channel_id,
a.timestamp,
b.timestamp,
a.value - b.value as `difference`
FROM table a
JOIN table b
ON a.channel_id = b.channel_id and a.timestamp <> b.timestamp and a.value > b.value
GROUP BY a.channel_id
ORDER BY a.channel_id
You can use a "correlated subquery" for this as seen below (also see this demo). When MySQL implements window functions such a LEAD() you could use those instead.
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`id` int, `channel_id` int, `timestamp` bigint, `value` int)
;
INSERT INTO Table1
(`id`, `channel_id`, `timestamp`, `value`)
VALUES
(4515, 7, 1519771680000, 7777),
(4518, 8, 1519772160000, 6666),
(4520, 7, 1519772340000, 8888)
;
Query 1:
select
id
, channel_id
, timestamp
, value
, nxt_value
, nxt_value - value as diff
from (
select
t1.id
, t1.channel_id
, t1.timestamp
, t1.value
, (select value from table1 as t2
where t2.channel_id = t1.channel_id
and t2.timestamp > t1.timestamp
order by t2.timestamp
limit 1) nxt_value
from table1 as t1
) as d
Results:
| id | channel_id | timestamp | value | nxt_value | diff |
|------|------------|---------------|-------|-----------|--------|
| 4515 | 7 | 1519771680000 | 7777 | 8888 | 1111 |
| 4518 | 8 | 1519772160000 | 6666 | (null) | (null) |
| 4520 | 7 | 1519772340000 | 8888 | (null) | (null) |
Starting from MySQL 8, you can use window functions, in case of which your query would look like this:
SELECT
id, channel_id, timestamp, value,
value - LAG(value, 1, 0) OVER (PARTITION BY channel_id ORDER BY timestamp) difference
FROM my_table
thanks for all your support. I tried a lot and created "my" solution based on a stored procedure. It is not as performant as it could be but it delivers the required values.
The code is running in a loop with a max size of repetitions in the script execution to avoid an endless step :)
#Auswahl größer CH10-Wert
set #var_max_ch10vz =
(
select max(data.timestamp)
from volkszaehler.data
where data.channel_id=10
)
;
#Auswahl kleinster offener Wert aus SBFSPOT
set #var_min_sbfspot =
(
select min(data.timestamp_unix*1000)
from sbfspot_u.data
where
data.timestamp_vzjoin is null
and data.timestamp_unix >1522096327
and data.timestamp_unix*1000 < #var_max_ch10vz
)
;
#Abgleich gegen VZ von unten
set #var_max_vz =
(
select min(data.timestamp)
from volkszaehler.data
where data.channel_id=10 and data.timestamp >= #var_min_sbfspot
)
;
#Abgleich gegen VZ von oben
set #var_min_vz =
(
select max(data.timestamp)
from volkszaehler.data
where data.channel_id=10 and data.timestamp <= #var_min_sbfspot
)
;
#Auswahl join Zeitstempel
set #vz_join_timestamp =
(
select tmp.uxtimestamp
from (
select #var_max_vz as uxtimestamp, abs(#var_min_sbfspot-#var_max_vz) as diff
UNION
select #var_min_vz as uxtimestamp, abs(#var_min_sbfspot-#var_min_vz) as diff
) tmp
order by tmp.diff asc
limit 1
)
;

Compare data using the year in a query

I have a data and they are recorded by each year, I am trying to compare two years( the past year and the current year) data within one mysql query
Below are my tables
Cost Items
| cid | items |
| 1 | A |
| 2 | B |
Cost
| cid | amount | year |
| 1 | 10 | 1 |
| 1 | 20 | 2 |
| 1 | 30 | 1 |
This is the result I am expecting when i want to compare the year 1 and year 2. Year 1 is the past year and year 2 is the current year
Results
items | pastCost | currentCost |
A | 10 | 20 |
A | 30 | 0 |
However the below query is what i used by gives a strange answer.
SELECT
IFNULL(ps.`amount`, '0') as pastCost
IFNULL(cs.`amount`, '0') as currentCost
FROM
`Cost Items` b
LEFT JOIN
`Cost` ps
ON
b.cID=ps.cID
AND
ps.Year = 1
LEFT JOIN
`Cost` cu
ON
b.cID=cu.cID
AND
cu.Year =2
This is the result i get from my query
items | pastCost | currentCost |
A | 10 | 20 |
A | 30 | 20 |
Please what am i doing wrong? Thanks for helping.
I'm missing something about your query; the SQL text shown can't produce that result.
There is no source for the items column in the SELECT list, and there is no table aliased as cs. (Looks like the expression in the SELECT list would need to be cu.amount
Aside from that, the results being returned look exactly like what we'd expect. Each row returned from year=2 is being matched with each row returned from year=1. If there were three rows for year=1 and two rows for year=2, we'd get six rows back... each row for year=1 "matched" with each row for year=2.
If (cid, year) tuple was UNIQUE in Cost, then this query would return a result similar to what you expect.
SELECT b.items
, IFNULL(ps.amount, '0') AS pastCost
, IFNULL(cu.amount, '0') AS currentCost
FROM `Cost Items` b
LEFT
JOIN `Cost` ps
ON ps.cid = b.cid
AND ps.Year = 1
LEFT
JOIN `Cost` cu
ON cu.cid = b.cid
AND cu.Year = 2
Since (cid, year) is not unique, you need some additional column to "match" a single row for year=1 with a single row for year=2.
Without some other column in the table, we could use an inline view to generate a value. I can illustrate how we can make MySQL return a resultset like the one you show, one way that could be done, but I don't think this is really the solution to whatever problem you are trying to solve:
SELECT b.items
, IFNULL(MAX(IF(a.year=1,a.amount,NULL)),0) AS pastCost
, IFNULL(MAX(IF(a.year=2,a.amount,NULL)),0) AS currentCost
FROM `Cost Items` b
LEFT
JOIN ( SELECT #rn := IF(c.cid=#p_cid AND c.year=#p_year,#rn+1,1) AS `rn`
, #p_cid := c.cid AS `cid`
, #p_year := c.year AS `year`
, c.amount
FROM (SELECT #p_cid := NULL, #p_year := NULL, #rn := 0) i
JOIN `Cost` c
ON c.year IN (1,2)
ORDER BY c.cid, c.year, c.amount
) a
ON a.cid = b.cid
GROUP
BY b.cid
, a.rn
A query something like that would return a resultset that looks like the one you are expecting. But again, I strongly suspect that this is not really the resultset you are really looking for.
EDIT
OP leaves comment with vaguely nebulous report of observed behavior: "the above solution doesnt work"
Well then, let's check it out... create a SQL Fiddle with some tables so we can test the query...
SQL Fiddle here http://sqlfiddle.com/#!9/e3d7e/1
create table `Cost Items` (cid int unsigned, items varchar(5));
insert into `Cost Items` (cid, items) values (1,'A'),(2,'B');
create table `Cost` (cid int unsigned, amount int, year int);
insert into `Cost` (cid, amount, year) VALUES (1,10,1),(1,20,2),(1,30,1);
And when we run the query, we get a syntax error. There's closing paren missing in the expressions in the SELECT list, easy enough to fix.
SELECT b.items
, IFNULL(MAX(IF(a.year=1,a.amount,NULL)),0) AS pastCost
, IFNULL(MAX(IF(a.year=2,a.amount,NULL)),0) AS currentCost
FROM `Cost Items` b
LEFT
JOIN ( SELECT #rn := IF(c.cid=#p_cid AND c.year=#p_year,#rn+1,1) AS `rn`
, #p_cid := c.cid AS `cid`
, #p_year := c.year AS `year`
, c.amount
FROM (SELECT #p_cid := NULL, #p_year := NULL, #rn := 0) i
JOIN `Cost` c
ON c.year IN (1,2)
ORDER BY c.cid, c.year, c.amount
) a
ON a.cid = b.cid
GROUP
BY b.cid
, a.rn
Returns:
items pastCost currentCost
------ -------- -----------
A 10 20
A 30 0
B 0 0

wordpress custom mysql query

In wordpress How can we fetch records in specific order within meta field value for eg I need to fetch all records where zip_code(meta key name) is all fields with 60007 first than all 60143 than 60191
Table drrr_posts
Id | post_name | content
2
3
4
22
32
43
Table drrr_postmeta
id | meta_key | meta_value | post_id
1 | zip_code | 60143 | 2
2 | zip_code | 60007 | 3
3 | zip_code | 60191 | 4
4 | zip_code | 60143 | 22
5 | zip_code | 60007 | 32
6 | zip_code | 60143 | 43
I think issue is I am passing ORDER BY FIELD( drrr_postmeta.meta_value not zip_code which is meta_key
In mysql I can easily pass the values in ORDERBY like
ORDER BY FIELD(name, 'B', 'A', 'D', 'E', 'C')
here is what I have now
My Query is
SELECT SQL_CALC_FOUND_ROWS drrr_posts.ID
FROM drrr_posts
INNER JOIN drrr_term_relationships ON ( drrr_posts.ID = drrr_term_relationships.object_id )
INNER JOIN drrr_postmeta ON ( drrr_posts.ID = drrr_postmeta.post_id )
INNER JOIN drrr_postmeta AS mt1 ON ( drrr_posts.ID = mt1.post_id )
WHERE 1 =1
AND drrr_posts.ID NOT
IN ( 91, 89, 87, 66 )
AND (
drrr_term_relationships.term_taxonomy_id
IN ( 11 )
)
AND drrr_posts.post_type = 'doctors'
AND (
(
drrr_posts.post_status = 'publish'
)
)
AND (
drrr_postmeta.meta_key = 'zip_code'
AND (
mt1.meta_key = 'zip_code'
AND CAST( mt1.meta_value AS SIGNED )
IN (
'60007', '60143', '60191', '60005', '60106', '60157', '60173', '60008', '60056', '60172'
)
)
)
GROUP BY drrr_posts.ID
ORDER BY FIELD( drrr_postmeta.meta_value, '60007', '60143', '60191', '60005', '60106', '60157', '60173', '60008', '60056', '60172' )
LIMIT 0 , 8
You can order your results by meta_key by adding one more conditional order by ,also your group by statement doesn't make any sense in absence of aggregate function ,for now you can do this
ORDER BY
drrr_postmeta.meta_key ='zip_code' desc,
FIELD( drrr_postmeta.meta_value, '60007', '60143', '60191', '60005', '60106', '60157', '60173', '60008', '60056', '60172' )
Using drrr_postmeta.meta_key ='zip_code' will result as a boolean and returns true if both matches so it will order results first by zip_code matching meta_key and then you field() function will order results accordingly

difficulties getting a 3 table join to return expected results

I'm having some difficulty getting to the bottom of this sql query.
Tables:
--Tickets-- --Finance-- --Access--
id_tickets id_finance id_access
name_tickets id_event id_event
cat_tickets id_tickets id_tickets
sold_finance scan_access
Finance and Access both contain a row for multiple of each ticket type as listed in tickets.
and I'm trying to get:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 3043 | 2571
season | 481 | 292
comp | 114 | 75
-------------------------------------
total | 3638 | 2938
The closest I've been to the result I've used:
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance INNER JOIN tickets ON finance.id_tickets = tickets.id_tickets
INNER JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235 AND finance.id_event = access.id_event
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
but that just returns:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 4945 | 4437
season | 954 | 599
comp | 342 | 375
-------------------------------------
total | 6241 | 5411
Any ideas where I could be going wrong?
Thanks!
The problem is the relation between access and finance tables, you have to join them. Even if you LEFT JOIN the table the predicate finance.id_event = access.id_event will make it INNER JOIN. As a work around, use UNION like this:
SELECT
tickets.cat_tickets,
SUM(CASE WHEN a.Type = 'f' THEN num ELSE 0 END) AS total_sold,
SUM(CASE WHEN a.Type = 'a' THEN num ELSE 0 END) AS total_scan
FROM tickets
LEFT JOIN
(
SELECT 'f' Type, id_tickets, sold_finance num
FROM finance f
WHERE id_event = 1
UNION ALL
SELECT 'a', id_tickets, scan_access
FROM access
WHERE id_event = 1
) a ON a.id_tickets = tickets.id_tickets
GROUP BY tickets.cat_tickets;
SQL Fiddle Demo
Although I am fully clear on what you want, just try this query if the result of this is what you are expecting.
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance LEFT JOIN tickets ON finance.id_tickets = tickets.id_tickets
LEFT JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
Disclaimer: This query is not tested due to incomplete data on the question.
SELECT z.Cat_tickets,
COALESCE(x.total_sold,0) total_sold,
COALESCE(y.total_scan,0) total_scan
FROM tickets z
LEFT JOIN
(
SELECT a.id_tickets,
a.cat_tickets,
SUM(b.sold_finance) total_sold
FROM tickets a
INNER JOIN finance b
ON a.id_tickets = b.id_tickets
WHERE id_event = 235
GROUP BY a.id_tickets, a.cat_tickets
) x ON z.id_tickets = x.id_tickets
LEFT JOIN
(
SELECT aa.id_tickets,
aa.cat_tickets,
SUM(bb.scan_access) total_scan
FROM tickets aa
INNER JOIN Access bb
ON aa.id_tickets = bb.id_tickets
WHERE id_event = 235
GROUP BY aa.id_tickets, aa.cat_tickets
) y ON z.id_tickets = y.id_tickets