Categorywise bulk update: MySql - mysql

I have a table for article that save the category for each article.
I want to update the sort order, but categorywise using a single query.
I am using this for data migration using bulk inserts and updated, so it looping the data is not a feasible solution.
id category_id sort_order
10 5 1
11 5 2
12 5 3
13 6 1
14 6 2
15 6 3
16 7 1
17 8 1
18 8 2
19 7 2
20 8 3
Is it possible to do this in a single query?
I have written the query for update sequentially on all rows. But unable to do it categorywise. The query i have written is below
SET #so = 0;
UPDATE article A
INNER JOIN category M ON A.category_id = M.id
SET A.sort_id = (#i := #i + 1)
WHERE A.user_id = 1;
SQLFIDDLE

I'd use a temporary table with a composite primary key to autogenerate the incrementing sort_order field...
http://sqlfiddle.com/#!9/3d59fe/1
-- populate test data
CREATE TABLE cp (id INT PRIMARY KEY,
category_id INT,
sort_order INT);
INSERT INTO cp VALUES
(10, 5, 1),
(11, 5, 2),
(12, 5, 3),
(13, 6, 1),
(14, 6, 2),
(15, 6, 3),
(16, 7, 1),
(17, 8, 1),
(18, 8, 2),
(19, 7, 2),
(20, 8, 3);
-- create temp table and generate sort order
CREATE TABLE tmp (
id INT NOT NULL,
category_id INT NOT NULL,
sort_order INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (category_id,sort_order)
) ENGINE=MyISAM;
INSERT INTO tmp (id, category_id)
SELECT id, category_id FROM cp
ORDER BY rand();
-- update original table
UPDATE cp JOIN tmp USING (id)
SET cp.sort_order = tmp.sort_order;

Related

How to get how many chapters read by user in mysql

I am having three tables bible_chapters, bible_reading_portions, user_bible_trackings, 1 chapter may have multiple bible portions and we are tracking portions in user_bible_trackings table. Below is my schema:-
bible_chapters
id chapter_name
1 Chpt1
2 Chpt2
3 Chpt3
bible_reading_portions
id bible_chapter_id portion_name
1 1 Chp1P1
2 2 Chp2P1
3 2 Chp2P2
4 2 Chp2P3
5 3 Chp3P1
user_bible_trackings
id bible_reading_portion_id user_id
1 1 1
2 2 1
3 3 1
4 4 1
5 1 1
6 2 1
7 3 1
8 4 1
9 1 1
10 2 1
So you see that above user_bible_trackings table user_id 1 have read Chpt1 3 times and Chpt2 2 times and user again started the chapter2 3rd time but its not complete yet beacuse chapt2 belongs to 3 portions,.... for the 3rd time user not read all the portions. So my expected output be like:-
user_id total_chapteres_read
1 5 // i.e means user read chpt1 3 times and chpt2 2 times so count will be 3+2=5
Can anyone help me how can i acheieve the same.
#Akina PLease check i have added the schema queries below:-
CREATE TABLE `bible_chapters` (
`id` int(11) NOT NULL,
`chapter_name` varchar(150) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bible_chapters` (`id`, `chapter_name`) VALUES
(1, 'Chp1'),
(2, 'Chp2'),
(3, 'Chp3');
---------------------
CREATE TABLE `bible_reading_portions` (
`id` int(11) NOT NULL,
`bible_chapter_id` int(11) NOT NULL,
`portion_name` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bible_reading_portions` (`id`, `bible_chapter_id`, `portion_name`)
VALUES
(1, 1, 'Chp1p1'),
(2, 2, 'Chp2p2'),
(3, 2, 'Chp2p2'),
(4, 2, 'Chp2p3');
-----------
CREATE TABLE `user_bible_trackings` (
`id` int(11) NOT NULL,
`bible_reading_portion_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user_bible_trackings` (`id`, `bible_reading_portion_id`, `user_id`) VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(4, 4, 1),
(5, 1, 1),
(6, 2, 1),
(7, 3, 1),
(8, 4, 1),
(9, 1, 1),
(10, 2, 1);
WITH
cte1 AS (
SELECT ubt.user_id,
bc.id bc_id, bc.chapter_name,
brp.id brp_id, brp.portion_name,
COUNT(*) cnt
FROM bible_chapters bc
JOIN bible_reading_portions brp ON bc.id = brp.bible_chapter_id
JOIN user_bible_trackings ubt ON brp.id = ubt.bible_reading_portion_id
GROUP BY 1,2,3,4,5
),
cte2 AS (
SELECT user_id, bc_id,
COUNT(brp_id) portions_count,
MIN(cnt) complete_readings
FROM cte1
GROUP BY 1,2
)
SELECT user_id, SUM(complete_readings) total_readings
FROM cte2
GROUP BY 1
fiddle with some comments.
The solution does not check does all portions of a chapter were read. For to take this into account you must compare portions_count (added but not used) with the same value for a chapter (obtained in separate CTE).

SQL - Get count of phone calls that resulted in meeting

I have a table named 'reports', something like this:
id
user_id
type
customer_id
text
created_at
1
1
1
3
....
2021-08-07 17:00:52
2
1
1
3
....
2021-08-12 10:11:11
3
1
1
9
....
2021-08-12 10:08:14
4
1
2
3
....
2021-08-12 10:04:08
5
1
2
9
....
2021-08-13 20:32:21
6
2
1
7
....
2021-08-13 20:34:17
7
2
2
8
....
2021-08-14 18:55:09
I want to get the count of rows that a user has submitted type 1 reports that result in a type 2 report.
Type 1 report means reporting a phone call to the customer and type 2 means meeting the customer. I want to receive the number of calls that resulted in an meeting.
For example, for user 1 should returns 3, because for customer 3, IDs 1 and 2 have led to ID 4, and for customer 9, ID 3 has led to ID 5.
But for user 2, ID 7 is type 2 but there is no previous type 1 report for customer 8, so it returns 0.
Schema (MySQL v5.7)
CREATE TABLE reports
(id int auto_increment primary key,
user_id int,
type int,
customer_id int,
text varchar(4),
created_at varchar(19)
);
INSERT INTO reports
(id, user_id, type, customer_id, text, created_at)
VALUES
(1, 1, 1, 3, '....', '2021-08-07 17:00:52'),
(2, 1, 1, 3, '....', '2021-08-12 10:11:11'),
(3, 1, 1, 9, '....', '2021-08-12 10:08:14'),
(4, 1, 2, 3, '....', '2021-08-12 10:04:08'),
(5, 1, 2, 9, '....', '2021-08-13 20:32:21'),
(6, 2, 1, 7, '....', '2021-08-13 20:34:17'),
(7, 2, 2, 8, '....', '2021-08-14 18:55:09');
Query #1
SELECT x.user_id
, COUNT(DISTINCT y.id) total
FROM reports x
LEFT
JOIN reports y
ON y.id<=x.id
AND y.user_id = x.user_id
AND y.customer_id = x.customer_id
AND y.type = 1
WHERE x.type = 2
GROUP
BY x.user_id;
user_id
total
1
3
2
0
View on DB Fiddle
You haven't shown how your are expecting results, but simply refer to User 1 and 2 and the total votes, you can try using a lateral join
select user_id, Coalesce(Sum(valid),0) rowcount
from reports r
join lateral (
select
case when exists (select * from reports rr
where rr.user_id=r.user_Id and rr.type=2 and rr.customer_id=r.customer_Id and r.type=1)
then 1 end valid
)x
group by User_Id
Example Fiddle
First you Count the number of customers that comply with your criterioa type and typoe 2. But ti get all user you need to join the list of users
I used LEFT join as also RIGHt JOIN in my example
CREATE TABLE reports
(`id` int, `user_id` int, `type` int, `customer_id` int, `text` varchar(4), `created_at` varchar(19))
;
INSERT INTO reports
(`id`, `user_id`, `type`, `customer_id`, `text`, `created_at`)
VALUES
(1, 1, 1, 3, '....', '2021-08-07 17:00:52'),
(2, 1, 1, 3, '....', '2021-08-12 10:11:11'),
(3, 1, 1, 9, '....', '2021-08-12 10:08:14'),
(4, 1, 2, 3, '....', '2021-08-12 10:04:08'),
(5, 1, 2, 9, '....', '2021-08-13 20:32:21'),
(6, 2, 1, 7, '....', '2021-08-13 20:34:17'),
(7, 2, 2, 8, '....', '2021-08-14 18:55:09')
;
SELECT IFNULL(Counts,0),t1.user_id
FROM (SELECT COUNT(distinct r.customer_id) counts,user_id
FROM reports r
WHERE type = 1 AND EXISTS(SELECT 1 FROM reports WHERE type = 2 AND customer_id = r.customer_id)
GROUP BY user_id) r RIGHT JOIN (SELECT DISTINCT user_id FROm reports) t1 ON r.user_id = t1.user_id
IFNULL(Counts,0) | user_id
---------------: | ------:
2 | 1
0 | 2
SELECT IFNULL(Counts,0),t1.user_id
FROM (SELECT DISTINCT user_id FROm reports) t1 LEFT JOIN (SELECT COUNT(distinct r.customer_id) counts,user_id
FROM reports r
WHERE type = 1 AND EXISTS(SELECT 1 FROM reports WHERE type = 2 AND customer_id = r.customer_id)
GROUP BY user_id) r ON r.user_id = t1.user_id
IFNULL(Counts,0) | user_id
---------------: | ------:
2 | 1
0 | 2
db<>fiddle here

MYSQL Query: find related entries from same table matching a condition determined through a second table

I'm new here, thanks for having me :)
Was hoping to get ideas for a solution to the following: I have a database for scientific specimens and experiments. Each specimen was tested at a certain combination of parameters. Parameters are varied in discrete steps (for example parameter 1: 2, 4 or 6 volts; parameter 3: 2, 10 or 20 amps). A group of specimens make up one experiment.
CREATE TABLE specimens (
id INTEGER PRIMARY KEY,
parameter1 INTEGER not null,
parameter2 INTEGER not null,
parameter3 INTEGER not null,
experiment_id INTEGER not null
);
CREATE TABLE experiments (
id INTEGER PRIMARY KEY
);
INSERT INTO `experiments` (`id`) VALUES
(1),
(2),
(3);
INSERT INTO `specimens` (`id`, `parameter1`, `parameter2`, `parameter3`, `experiment_id`) VALUES
(1, 2, 2, 2, 1),
(2, 2, 2, 10, 1),
(3, 2, 2, 20, 1),
(4, 2, 2, 2, 2),
(5, 4, 2, 2, 2),
(6, 6, 2, 2, 2),
(7, 2, 2, 2, 3),
(8, 4, 2, 10, 3),
(9, 6, 2, 20, 3);
I'm trying to put together a query that does the following:
Select all specimens from the database, for which there exists at least one other specimen within the same experiment, that was tested at a different level of a certain factor.
For example:
condition is: distinct parameter1 -> result is: specimens
4,5,6,7,8,9
condition is: distinct parameter2 -> no results
condition is: distinct parameter3 -> result
is: specimens 1,2,3,7,8,9
I'm (obviously) not a pro at this, but so far I figured it can't be done with JOIN, as I need to vertically append rows to my set of results, but it can't be a UNION query either, because the second query can't interact with the first one. My current progress is something like:
SELECT specimens1.*
FROM specimens AS specimens1
WHERE
specimens1.id = 2
OR specimens1.id IN (
SELECT specimens2.id
FROM specimens AS specimens2
WHERE specimens2.experiment_id = specimens1.experiment_id
)
Which turned out to be nonsense. I hoped it would at least get me specimens 1, 2 and 3 for a start, as they belong to the same experiment. It doesn't, though. Also, I have no idea how to implement the "at least one other level of a certain factor within the same experiment" condition.
Does anyone have a hint?
Thank you for your time!
Cheers, Max
A union does help as does group concat and left joining all parameters.
DROP TABLE IF EXISTS SPECIMENS,EXPERIMENTS;
CREATE TABLE specimens (
id INTEGER PRIMARY KEY,
parameter1 INTEGER not null,
parameter2 INTEGER not null,
parameter3 INTEGER not null,
experiment_id INTEGER not null
);
CREATE TABLE experiments (
id INTEGER PRIMARY KEY
);
INSERT INTO `experiments` (`id`) VALUES
(1),
(2),
(3);
INSERT INTO `specimens` (`id`, `parameter1`, `parameter2`, `parameter3`, `experiment_id`) VALUES
(1, 2, 2, 2, 1),
(2, 2, 2, 10, 1),
(3, 2, 2, 20, 1),
(4, 2, 2, 2, 2),
(5, 4, 2, 2, 2),
(6, 6, 2, 2, 2),
(7, 2, 2, 2, 3),
(8, 4, 2, 10, 3),
(9, 6, 2, 20, 3);
select a.parameter, group_concat(gc) vals from
(
(select 'parameter1' parameter union select 'parameter2' union all select 'parameter3') a
left join
(
select e.id,'parameter1' as parameter,group_concat(s.id) gc
from experiments e
join specimens s on s.experiment_id = e.id
group by e.id having count(distinct parameter1) > 1
union all
select e.id,'parameter2' as parameter,group_concat(s.id) gc
from experiments e
join specimens s on s.experiment_id = e.id
group by e.id having count(distinct parameter2) > 1
union all
select e.id,'parameter3' as parameter,group_concat(s.id) gc
from experiments e
join specimens s on s.experiment_id = e.id
group by e.id having count(distinct parameter3) > 1
) b on b.parameter = a.parameter
)
group by a.parameter;
+------------+-------------+
| parameter | vals |
+------------+-------------+
| parameter1 | 4,5,6,7,8,9 |
| parameter2 | NULL |
| parameter3 | 1,2,3,7,8,9 |
+------------+-------------+
3 rows in set (0.102 sec)
Thanks a lot, P.Salmon! From your answer I was able to construct the following, which gets the result I actually had in mind:
SELECT * FROM specimens
HAVING FIND_IN_SET(id, (SELECT group_concat(gc)
FROM
(SELECT 'parameter1' parameter)
a LEFT JOIN
(
SELECT e.id,'parameter1' AS parameter, GROUP_CONCAT(s.id) gc
FROM experiments e
JOIN specimens s ON s.experiment_id = e.id
GROUP BY e.id
HAVING COUNT(DISTINCT parameter1) > 1
)
b ON b.parameter = a.parameter
)) > 0
I was looking for the actual data rows of all specimens meeting one distinct-parameter-criterion at a time, rather than a full set of all possible results. Example above is for parameter1 only, then.

Case, group by , join on multiple table

I have 3 tables transaction , store and date. A column in store table needs to be assigned values based on conditions and that new column needs to be used in group by.
ASK is to find ` total sales across different banners for a particular time period.
i am using following query..
"""select sum(net_spend) as sales , d.fis_week_id, st.banner
from ( select s*,
CASE WHEN st.format IN ('S','S MINI','S HYPER') THEN 'S'
WHEN st.format = 'CHECKERS' THEN 'CHECKERS'
ELSE st.format END AS banner
from store_dim s) st
from transaction_item_fct tr
inner join date_dim d on d.date_id = tr.date_id
inner join store_dim_c s on st.store_id = tr.store_id
where d.fis_week_id >=201809 and d.fis_week_id<=201813
and tr.store_id = st.store_id
group by st.banner, d.fis_week_id
"""
Where I am getting wrong?
Below is the fabricated tables' data
Transaction table-
store_id week_id net_spend
1 12 345
1 11 788
2 13 556
3 11 300
Store table
store_id format
1 S
2 S MINI
3 S Hyper
4 Checker
Date table
week_id fis_week_id
11 201712
12 201717
Result expected is
week_id banner spend
11 S 888
11 Hyper 666
It's not 100% clear from your question but I think this query will do what you want. You will need to change the WHERE condition on d.fis_week_id as appropriate for your needs, I have made it appropriate for the demo case I set up.
SELECT d.week_id, st.banner, SUM(t.net_spend) AS sales, d.fis_week_id
FROM date_dim d
LEFT JOIN transaction_item t ON t.week_id = d.week_id
JOIN (SELECT store_id,
CASE WHEN format IN ('S', 'S MINI', 'S Hyper') THEN 'S'
WHEN format = 'Checker' THEN 'Checker'
ELSE format
END AS banner
FROM store_dim s) st
ON st.store_id = t.store_id
WHERE d.fis_week_id BETWEEN 201712 AND 201720
GROUP BY d.week_id, st.banner
I've expanded your demo data out a bit and created a test case at SQLFiddle:
CREATE TABLE transaction_item
(`store_id` int, `week_id` int, `net_spend` int);
INSERT INTO transaction_item
(`store_id`, `week_id`, `net_spend`)
VALUES (1, 12, 345), (1, 11, 788), (2, 13, 556), (3, 11, 300),
(4, 11, 440), (4, 12, 123), (5, 11, 100), (6, 13, 444);
CREATE TABLE store_dim
(`store_id` int, `format` varchar(7));
INSERT INTO store_dim
(`store_id`, `format`)
VALUES (1, 'S'), (2, 'S MINI'), (3, 'S Hyper'), (4, 'Checker'), (5, 'Checker'), (6, 'Other');
CREATE TABLE date_dim
(`week_id` int, `fis_week_id` int);
INSERT INTO date_dim
(`week_id`, `fis_week_id`)
VALUES (11, 201712), (12, 201717), (13, 201720);
Output:
week_id banner sales fis_week_id
11 Checker 540 201712
11 S 1088 201712
12 Checker 123 201717
12 S 345 201717
13 Other 444 201720
13 S 556 201720

How to join two mysql table and retrieve latest results from joined table?

I have two tables. I need to join these two tables and retrieve latest status from execution table. How can I retrieve?
My schema and data:
CREATE TABLE test
(`id` serial primary key, `ref_id` int, `ref_name` varchar(7))
;
INSERT INTO test
(`id`, `ref_id`, `ref_name`)
VALUES
(1, 1, 'trial'),
(2, 3, 'test'),
(3, 7, 'testing')
;
CREATE TABLE execution
(`id` serial primary key, `ref_id` int, `status` varchar(11))
;
INSERT INTO execution
(`id`, `ref_id`, `status`)
VALUES
(1, 1, 'Completed'),
(2, 2, 'Completed'),
(3, 1, 'Completed'),
(4, 3, 'In progress'),
(5, 3, 'To do'),
(6, 2, 'In progress'),
(7, 1, 'Completed'),
(7, 1, 'To do')
;
Expected result is here below.
ref_id | ref_name | status |
3 | testing | In progress |
2 | test | To do |
1 | trial | To do |
I have tried with below query:
SELECT
ref_id,
ref_name,
status
FROM
test
JOIN execution ON test.ref_id = execution.ref_id
GROUP BY `ref_id`
ORDER BY `ref_id` DESC;
This query retrieves the status, but the retrieved status is not a latest one. How can retrieve the latest status by joining these two tables.
you can use below query
select T2.ref_id,T2.ref_name,OE.status from
(
select t1.ref_id,t1.ref_name,e.id from test t1 inner join
(select max(id) as id,ref_id from execution group by ref_id) as e
on
t1.ref_id=e.ref_id
) as T2
inner join execution OE on T2.id=OE.id
https://www.db-fiddle.com/f/rvnm8APX27dmW9a84JkCsS/1
It seems you have given in-correct data as an example as ref_id 7 not found in
execution table. However this might help you
SELECT b.ref_id,
b.ref_name,
a.status
FROM execution a
JOIN (SELECT MAX(id) id ,ref_id
FROM execution
GROUP BY ref_id) a1
USING(id,ref_id)
JOIN test b ON a.ref_id = b.ref_id ORDER BY ref_id DESC;