Sql update where left join count equal to 3 - mysql

Hi I'm trying to build a sql query where I update the value of a table where the left join of another table is equal to 3.
Example when a vehicle has 3 photos.
The query I've written thus far, it seems to fail with group by though.
UPDATE domain.vehicle_listing AS t0 LEFT OUTER JOIN photo AS t1 ON t0.id = t1.vehicle_listing_id
SET t0.active = 0
WHERE `create_date` >= '2015-5-2'
AND user_profile_id is not null
AND t0.active = 1
GROUP BY t1.vehicle_listing_id
HAVING COUNT(DISTINCT t1.id) = 3
ORDER BY create_date desc;
Vehicle_Listing
id
Photo
id, vehicle_listing_id, photo_url
OneToMany relationship with photo.

You can also use exists
UPDATE vehicle_listing AS t0
SET t0.active = 0
WHERE t0.`create_date` >= '2015-05-02'
AND t0.user_profile_id is not null
AND t0.active = 1
AND EXISTS (
SELECT 1
FROM photo
WHERE vehicle_listing_id=t0.id
GROUP BY vehicle_listing_id
HAVING COUNT(DISTINCT id) = 3
)
Sample data for vehicle_listing
INSERT INTO vehicle_listing
(`id`, `title`, `create_date`, `active`,user_profile_id)
VALUES
(1, 'test', '2015-05-02 00:00:00', 1,1),
(2, 'test1', '2015-05-02 00:00:00', 1,1)
;
Sample data for photo
INSERT INTO photo
(`id`, `vehicle_listing_id`, `photo_url`)
VALUES
(1, 1, 'image.jpg'),
(2, 1, 'image.jpg'),
(3, 1, 'image.jpg'),
(4, 2, 'image.jpg'),
(5, 2, 'image.jpg')
;
Sample Output
id title create_date active user_profile_id
1 test May, 02 2015 00:00:00 0 1
2 test1 May, 02 2015 00:00:00 1 1
DEMO

It is silly to use a left join for this. You want inner join:
UPDATE cardaddy.vehicle_listing vl INNER JOIN
(SELECT p.vehicle_listing_id, count(*) as cnt
FROM photo p
GROUP BY p.vehicle_listing_id
) p
ON vl.id = p.vehicle_listing_id AND
p.cnt = 3
SET vl.active = 0
WHERE vl.create_date >= '2015-05-02' AND
vl.user_profile_id IS NOT NULL AND
vl.active = 1;
(Assuming that user_profile_id is in vehicle_listing.)

UPDATE cardaddy.vehicle_listing AS t0
LEFT OUTER JOIN (
SELECT vehicle_listing_id, count(1) AS counter
FROM photo
GROUP BY vehicle_listing_id
) AS t1
ON t0.id = t1.vehicle_listing_id
AND t1.counter = 3
SET t0.active = 0
WHERE `create_date` >= '2015-5-2'
AND user_profile_id IS NOT NULL
AND t0.active = 1
AND t1.vehicle_list_is IS NOT NULL

Related

Displayed values are not what they should be

There are 2 tables ost_ticket and ost_ticket_action_history.
create table ost_ticket(
ticket_id int not null PRIMARY KEY,
created timestamp,
staff bool,
status varchar(50),
city_id int
);
create table ost_ticket_action_history(
ticket_id int not null,
action_id int not null PRIMARY KEY,
action_name varchar(50),
started timestamp,
FOREIGN KEY(ticket_id) REFERENCES ost_ticket(ticket_id)
);
In the ost_ticket_action_history table the data is:
INSERT INTO newdb.ost_ticket_action_history (ticket_id, action_id, action_name, started) VALUES (1, 1, 'Consultation', '2022-01-06 18:30:29');
INSERT INTO newdb.ost_ticket_action_history (ticket_id, action_id, action_name, started) VALUES (2, 2, 'Bank Application', '2022-02-06 18:30:45');
INSERT INTO newdb.ost_ticket_action_history (ticket_id, action_id, action_name, started) VALUES (3, 3, 'Consultation', '2022-05-06 18:42:48');
In the ost_ticket table the data is:
INSERT INTO newdb.ost_ticket (ticket_id, created, staff, status, city_id) VALUES (1, '2022-04-04 18:26:41', 1, 'open', 2);
INSERT INTO newdb.ost_ticket (ticket_id, created, staff, status, city_id) VALUES (2, '2022-05-05 18:30:48', 0, 'open', 3);
INSERT INTO newdb.ost_ticket (ticket_id, created, staff, status, city_id) VALUES (3, '2022-04-06 18:42:53', 1, 'open', 4);
My task is to get the conversion from the “Consultation” stage to the “Bank Application” stage broken down by months (based on the start date of the “Bank Application” stage).Conversion is calculated according to the following formula: (number of applications with the “Bank Application” stage / number of applications with the “Consultation” stage) * 100%.
My request is like this:
select SUM(action_name='Bank Application')/SUM(action_name='Consultation') * 2 as 'Conversion' from ost_ticket_action_history JOIN ost_ticket ot on ot.ticket_id = ost_ticket_action_history.ticket_id where status = 'open' and created > '2020 -01-01 00:00:00' group by action_name,started having action_name = 'Bank Application';
As a result I get:
Another query:
SELECT
SUM(CASE
WHEN b.ticket_id IS NOT NULL THEN 1
ELSE 0
END) / COUNT(*) conversion,
YEAR(a.started) AS 'year',
MONTH(a.started) AS 'month'
FROM
ost_ticket_action_history a
LEFT JOIN
ost_ticket_action_history b ON a.ticket_id = b.ticket_id
AND b.action_name = 'Bank Application'
WHERE
a.action_name = 'Consultation'
AND a.status = 'open'
AND a.created > '2020-01-01 00:00:00'
GROUP BY YEAR(a.started) , MONTH(a.started)
I apologize if I didn't write very clearly. Please explain what to do.
Like I explained in my comment, you exclude rows with your having clause.
I will show you in the next how to debug.
First check what the raw result of the select query is.
As you see, when you remove the GROUP BY and see what you actually get is only 1 row with bank application, because the having clause excludes all other rows
SELECT
*
FROM
ost_ticket_action_history
JOIN
ost_ticket ot ON ot.ticket_id = ost_ticket_action_history.ticket_id
WHERE
status = 'open'
AND created > '2020-01-01 00:00:00'
GROUP BY
action_name, started
HAVING
action_name = 'Bank Application';
Output:
ticket_id
action_id
action_name
started
ticket_id
created
staff
status
city_id
2
2
Bank Application
2022-02-06 18:30:45
2
2022-05-05 18:30:48
0
open
3
Second step, see what the result set is without calculating anything.
As you can see you make a division with 0, what you have learned in school, is forbidden, hat is why you have as result set NULL
SELECT
SUM(action_name = 'Bank Application')
#/
,SUM(action_name = 'Consultation') * 2 AS 'Conversion'
FROM
ost_ticket_action_history
JOIN
ost_ticket ot ON ot.ticket_id = ost_ticket_action_history.ticket_id
WHERE
status = 'open'
AND created > '2020-01-01 00:00:00'
GROUP BY action_name , started
HAVING action_name = 'Bank Application';
SUM(action_name = 'Bank Application') | Conversion
------------------------------------: | ---------:
1 | 0
db<>fiddle here
#Third what you can do exclude a division with 0, here i didn't remove all othe rows as this is only for emphasis
SELECT
SUM(action_name = 'Bank Application')
/
SUM(action_name = 'Consultation') * 2 AS 'Conversion'
FROM
ost_ticket_action_history
JOIN
ost_ticket ot ON ot.ticket_id = ost_ticket_action_history.ticket_id
WHERE
status = 'open'
AND created > '2020-01-01 00:00:00'
GROUP BY action_name , started
HAVING SUM(action_name = 'Consultation') > 0;
| Conversion |
| ---------: |
| 0.0000 |
| 0.0000 |
db<>fiddle here
Final words,
If you get a strange result, simply go back remove everything that doesn't matter and try to get all values, so hat you can check your math

Mysql query to decide the type if group by value is greater than 1 consider as type 2 else 1

I want to write a case condition in mysql query when grouped by channelvalue if the count is more than 1 it is considered as type_id 3 if there is no duplicates for the channelvalue then the type_id should be 2
else 0
select b.ChannelValue
case
when count(*),ChannelValue from tableb group by ChannelValue having count(*)=1 then 2
when count(*),ChannelValue from tableb group by ChannelValue having count(*)>1 then 3
else 0 END AS type_id
from tablea a inner join tableb b
on a.ChannelValue = b.ChannelValue;
Help me out !
You could use something like below:
select ChannelValue,
case
when (
select count(*) from tableb
group by tableb.ChannelValue
having tableb.ChannelValue = tablea.ChannelValue) = 1 then 2
when(
select count(*) from tableb
group by tableb.ChannelValue
having tableb.ChannelValue = tablea.ChannelValue) > 1 then 3
else 0
END as type_id
from tablea;
Say if you have this test data:
INSERT INTO tablea (PersonID, ChannelValue)
VALUES (1, 100),
(2, 200),
(3, 300);
INSERT INTO tableb (testID, ChannelValue, characterid)
VALUES (1, 100, 1),
(2, 100,2),
(3, 300, 3);
The query would return:
ChannelValue
type_id
100
3
200
0
300
2

MySQL - conditional select in group

I have a simple table with several rows and I would like to group them by id_room and select value only when condition is true. Problem is that condition is always false even there is a row with right date column year_month.
Here is schema:
CREATE TABLE tbl_account_room (
`id` int,
`year_month` date,
`value` int,
`id_room` int
);
INSERT INTO tbl_account_room
(`id`, `year_month`, `value`, `id_room`)
VALUES
(1, '2016-08-01', 1, 300),
(2, '2016-09-01', 2, 300),
(3, '2016-10-01', 3, 300);
and here query:
SELECT
(case when '2016-10-01' = ar.year_month then ar.value else 0 end) as total
FROM tbl_account_room AS ar
WHERE ar.year_month >= "2016-08-01"
AND ar.year_month <= "2016-11-01"
and ar.id_room = '300'
GROUP BY ar.id_room
LIMIT 10
Here is SQL Fiddle
In column total I'm getting 0 and I would like to get value 3 because year_month is 2016-10-01. Why this happens?
You certainly don't need that CASE condition and include that condition in your WHERE clause rather like
SELECT
ar.value as total,
GROUP_CONCAT(ar.year_month)
FROM tbl_account_room AS ar
WHERE ar.year_month = '2016-10-01'
GROUP BY ar.id_room;
Not sure why you want the result like that, here you can use self join to do that:
SELECT
MAX(t1.value) as total,
GROUP_CONCAT(ar.year_month)
FROM tbl_account_room AS ar
LEFT JOIN tbl_account_room AS t1
ON ar.id_room = t1.id_room
AND ar.year_month = t1.year_month
AND t1.year_month = '2016-10-01'
WHERE ar.year_month >= "2016-08-01"
AND ar.year_month <= "2016-11-01"
and ar.id_room = '300'
GROUP BY ar.id_room
LIMIT 10;
and here is SQLFiddle Demo.

MySQL finding gaps in column with multiple ID

I would like to find gaps in following table:
create table sequence
(
`Id` int,
`Value` int not null,
PRIMARY KEY (`Id`,`Value`)
);
insert into sequence
( `Id`, `Value` )
values
(10, 0 ),
(10, 1 ),
(10, 4 ),
(10, 5 ),
(10, 6 ),
(10, 7 ),
(11, 0 ),
(11, 1 ),
(11, 2 ),
(11, 5 ),
(11, 7 );
Expeced result is somthing like:
10 | 2-3
11 | 3-4
11 | 6
or
10 | 2
10 | 3
11 | 3
11 | 4
11 | 6
I know, that value of the colum 'Value' is between 0 and 7.
Is it possible to do it using MySQL?
EDIT 1
Based on answers I come with this:
SELECT Tbl1.Id,
startseqno,
Min(B.Value) - 1 AS END
FROM (SELECT Id,
Value + 1 AS StartSeqNo
FROM SEQUENCE AS A
WHERE NOT EXISTS (SELECT *
FROM SEQUENCE AS B
WHERE B.Id = A.id
AND B.Value = A.Value + 1)
AND Value < (SELECT Max(Value)
FROM SEQUENCE B
WHERE B.Id = A.Id)) AS Tbl1,
SEQUENCE AS B
WHERE B.Id = Tbl1.Id
AND B.Value > Tbl1.startseqno
But now I am getting just
10 | 2 | 3
Please, does somebody know, how to fix it?
sqlfiddle
You can do this with not exists:
select s.*
from sequence s
where not exists (select 1 from sequence s2 where s2.id = s.id and s2.value = s.value + 1) and
exists (select 1 from sequence s2 where s2.id = s.id and s2.value > s.value);
The exists clause is important so you don't report the final value for each id.
EDIT:
Here is a better approach:
select s.value + 1 as startgap,
(select min(s2.value) - 1 from sequence s2 where s2.id = s.id and s2.value > s.value) as endgap
from sequence s
where not exists (select 1 from sequence s2 where s2.id = s.id and s2.value = s.value + 1) and
exists (select 1 from sequence s2 where s2.id = s.id and s2.value > s.value);

SQL: find all items on left side where right side items all have specific field value

There is a table job that contains data as shown below:
Id Status
-----------
1 NEW
2 NEW
There is a table item that contains data as shown below:
Id Status JobId
---------------------
1 NEW 1
2 PROCESSED 1
3 NEW 1
4 PROCESSED 2
5 PROCESSED 2
I want to run a query, that will return all Jobs whose "children" all have a status of X
Pseudo-SQL:
SELECT * FROM Job WHERE status = 'NEW' AND Items for Job WHERE all items status = PROCESSED
That should return
Id Status
-----------
2 NEW
Because all of Job 2 items have status = PROCESSED.
Job 1 does not appear because it has items with the unwanted status NEW
SELECT * from job where Id not in (SELECT JobId from item where Status <> 'PROCESSED');
This will return all from job where id is not in result of all jobids which have status different from 'PROCESSED'.
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE job
(`Id` int, `Status` varchar(3))
;
INSERT INTO job
(`Id`, `Status`)
VALUES
(1, 'NEW'),
(2, 'NEW')
;
CREATE TABLE item
(`Id` int, `Status` varchar(9), `JobId` int)
;
INSERT INTO item
(`Id`, `Status`, `JobId`)
VALUES
(1, 'NEW', 1),
(2, 'PROCESSED', 1),
(3, 'NEW', 1),
(4, 'PROCESSED', 2),
(5, 'PROCESSED', 2)
;
Query 1:
SELECT *
FROM job
WHERE NOT EXISTS
(SELECT 1
FROM item
WHERE job.Id = item.JobId AND item.Status <> 'PROCESSED')
Results:
| ID | STATUS |
|----|--------|
| 2 | NEW |
SELECT j.* FROM Job j
WHERE not exists (select 1 from item i where i.JobId = j.id and i.Status != 'PROCESSED')
and exists (select 1 from item i where i.JobId = j.id and i.Status = 'PROCESSED')
and j.status = 'NEW';
Or
SELECT j.* FROM Job j
WHERE j.id in
(select jobId from (
select jobId, count(distinct status) n_all,
count(distinct case when status = 'PROCESSED'
then status else null
end) n_processed
from item group by jobId
) t
where n_all = n_processed
)
and j.status = 'NEW';