Updating SQL Query on multiple values - mysql

I have two models one is student_profile where I have university field to show university name. I have a list of universities where I need to update another table called Package only if one of the university exists in table. Table has 1000 records and I need to update all the entries with one query.
If university a, b, c, d exists in student_profile.
Update few "Package" table fields.
My tables:
+---------------------------+
| student_profile |
+---------------------------+
| id | int(11) |
| first_name | varchar(45) |
| last_name | varchar(45) |
| university | varchar(45) |
+---------------------------+
+---------------------------+
| package |
+---------------------------+
| student_id | int(11) |
| is_active | tinyint |
| package_type| varchar(45) |
+---------------------------+
ForeignKeys in StudentProfile Table:
name = student_package
schema = mydb
Column = student_id
reference Schema = mydb
referenced table = student_profile
referenced column= id
If university exists I need to set is_active=True and set package.student_id as student_profile.id and package.package_type as 'UniverityEnrolled'.

To figure something like this out, start with a SELECT that outputs the records to be updated.
Then when it is working, convert to an update statement.
SELECT *
FROM `StudentProfile` a
JOIN `Package` b
ON a.`id` = b.`student_id`
WHERE `university` in ('a','b','c');
UPDATE `StudentProfile` a
SET `is_active` = 1
JOIN `Package` b
ON a.`id` = b.`student_id`
WHERE `university` in ('a','b','c');

Based on what I understand of the question, this may be your solution:
UPDATE package
SET is_active = 1,package_type = "UniversityEnrolled"
WHERE student_id IN
(SELECT id FROM student_profile WHERE university IN ("a","b","c","d"))

Related

confusing MySqL JOIN

Unfortunately, I'm not sure if there is a specific name for the query I am attempting to write. My problem is the following, I have created two temporary tables, one with a list of customers who have "opted out" of a communication, either on IVR or through email.
mysql> desc tt_customers;
+------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | MUL | 0 | |
| name | varchar(40) | NO | | NULL | |
+------------------+------------------+------+-----+---------+-------+
mysql> desc tt_opt_outs;
+-----------------------+----------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+----------------------------------------+------+-----+---------+-------+
| customer_id | int(10) unsigned | NO | MUL | NULL | |
| event_type | enum('PRE_PEAK_TIME','POST_PEAK_TIME' | YES | | NULL | |
| notification_channel | enum('EMAIL','IVR') | NO | | NULL | |
+-----------------------+----------------------------------------+------+-----+---------+-------+
Not all customers in the customer table will be in the opt out table. Customers in the opt out table may be in there with an opt out for EMAIL, IVR or both, and for any event type. I'd like to create a report with the following column headers customer_id, name, IVR Optout, Email Optout, where the IVR and Email opt out columns are regardless of the opt out event_type. I'm not sure how to structure a join/subquery/union or whatever I'd need here to create the exact query I need. Any help would be appreciated!
Apart from the case statement you can also use left outer join.
Query (left outer join)
select c.id as customer_id , c.name,ti.notification_channel as IVR,
te.notification_channel as EMAIL from tt_customers c
left outer join tt_opt_outs ti on c.id = ti.customer_id and ti.notification_channel = 'IVR'
left outer join tt_opt_outs te on c.id = te.customer_id and te.notification_channel = 'EMAIL'
Output:
Data Set-Up:
create table tt_customers (id int(10), name varchar(40));
create table tt_opt_outs (customer_id int(10), event_type enum('PRE_PEAK_TIME','POST_PEAK_TIME'), notification_channel enum('EMAIL','IVR') );
insert into tt_customers values (1,"all in");
insert into tt_customers values(2,"email out");
insert into tt_customers values(3,"ivr out");
insert into tt_customers values(4,"all out");
insert into tt_opt_outs values(2,'PRE_PEAK_TIME','EMAIL');
insert into tt_opt_outs values(3,'PRE_PEAK_TIME','IVR');
insert into tt_opt_outs values(4,'PRE_PEAK_TIME','EMAIL');
insert into tt_opt_outs values(4,'PRE_PEAK_TIME','IVR');
SQL Fiddle : http://sqlfiddle.com/#!9/0e82a7/17
Below is the SQL that will give you the desired result to you:
create table tt_customers(id int,name varchar(40));
create table tt_opt_outs(customer_id int,event_type enum('PRE_PEAK_TIME','POST_PEAK_TIME'),notification_channel enum('EMAIL','IVR'));
insert into tt_customers values(1,'ABC');
insert into tt_customers values(2,'XYZ');
insert into tt_opt_outs values(1,'PRE_PEAK_TIME','EMAIL');
insert into tt_opt_outs values(2,'POST_PEAK_TIME','IVR');
Your query for desired result:
select c.id as customer_id,
c.name,
case when t.notification_channel = 'IVR' then 'Yes' else null end ivr_optout,
case when t.notification_channel = 'EMAIL' then 'Yes' else null end email_optout
from tt_customers c
left join tt_opt_outs t
on (c.id = t.customer_id);

MySQL indexing to efficiently query table join with many to many relationship

I've been struggling to create the correct index to improve performance for a specific query we run on our database, I hope one of you can help point me in the right direction.
I have 2 tables as per below. I have a query to find all employees of companies that belong to a specific category with first_name like "Be%" for example. I've tried creating a multiple index on category_id, company_id but this hasn't helped. What should be the correct way to index my tables to achieve better performance for this query? Thank you in advance.
SELECT
e.*
FROM employee e
INNER JOIN company c ON e.company_id = c.company_id
WHERE c.category_id = 6
AND e.first_name LIKE "Be%"
GROUP BY e.employee_id
TABLE company
| company_id | category_id |
+------------+-------------+
| ... | ... |
+------------+-------------+
| 47 | 6 |
+------------+-------------+
| .. | ... |
+------------+-------------+
| 252 | 6 |
+------------+-------------+
TABLE employee
| employee_id | company_id | first_name | ... |
+-------------+------------+------------+-----+
| 2582250 | 47 | Ben | ... |
+-------------+------------+------------+-----+
| 3447890 | 252 | Ryan | ... |
+-------------+------------+------------+-----+
| 7125966 | 252 | Beth | ... |
+-------------+------------+------------+-----+
| ... | ... | ... | ... |
+-------------+------------+------------+-----+
CREATE TABLES below and sqlfiddle.
CREATE TABLE company (
`company_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`category_id` INT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=InnoDB;
CREATE TABLE employee (
`employee_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`company_id` INT UNSIGNED NOT NULL,
`first_name` VARCHAR(255)
) ENGINE=InnoDB;
You must have indexes in many:many tables. Follow the advice outlined here.
WHERE c.category_id = 6
AND e.first_name LIKE "Be%"
needs
c: INDEX(category_id, company_id) -- which will be called for in the link above
e: INDEX(first_name, employee_id)
The Optimizer will either start with c, then reach into e. Or vice versa. I am providing you the optimal indexes for either direction.

select most recently added record with value in MySQL

I have a table with the following structure
CREATE TABLE `data` (
`type` varchar(64) DEFAULT NULL,
`subscr_id` varchar(64) DEFAULT NULL
)
In this table, there are many records with subscr_id of id100. I would like to select a record with subscr_id of id100, that was added to the table most recently.
How can I do that?
You add an ID - Indentify column. It's best performance in this/your situation.
ALTER TABLE data ADD COLUMN id INT NULL AUTO_INCREMENT FIRST, ADD KEY(id);
Run the below SQL, you will receive the record with subscr_id of id100, that was added to the table most recently most recently.
SELECT * FROM `data` WHERE subscr_id = 'id100' ORDER BY id DESC LIMIT 1;
I think you have to improve your table design and add auto-inctemental primary key or created_at field.
But if you can't do it or you need run query just once, you can try this approach (it's a bit tricky but it works 😉).
In general recent record will be present at the end of the table. For example we have table like this:
+------+-----------+
| type | subscr_id |
+------+-----------+
| a | id100 |
| b | id100 |
| c | id100 |
| a | id200 |
| b | id200 |
| d | id100 |
| c | id200 |
| e | id100 |
+------+-----------+
And here wee need calculate total count of interesting rows and use it for offset, like this:
set #offset = (select count(*) from data where subscr_id = 'id100') - 1;
set #sql = concat(
"select * from data where subscr_id = 'id100' limit 1 offset ",
#offset
);
prepare stmt1 from #sql;
execute stmt1;
The result will look like this:
+------+-----------+
| type | subscr_id |
+------+-----------+
| e | id100 |
+------+-----------+

Mysql query of multiple tables joined

I have the following tables:
machine_machine
id | machineid
1 | EE100034442
item_item
id | upc | name
2 | 10001 | Snickers
machine_setup
id | machine_id | selection | item_id
3 | 1 | A1 | 1
Im trying to get the following output by joining the tables.
machine_setup.machine_id=machine_machine.machineid, machine_setup.selection, item_item.upc, item_item.name
EE100034442 A1 10001 Snickers
Table machine_setup will by the main referenced table as it has multiple selection for each machine_id.
Based on the only id's I can see at the moment to join on, consider this:
create table machine_machine
( id int auto_increment primary key,
machineid varchar(50) not null
);
create table item_item
( id int auto_increment primary key,
upc varchar(30) not null,
name varchar(100) not null
);
create table machine_setup
( id int auto_increment primary key,
machine_id int not null,
selection varchar(30) not null
);
insert machine_machine(machineid) values ('EE100034442');
insert item_item(upc,name) values ('10001','Snickers');
insert machine_setup(machine_id,selection) values (1,'A1'),(1,'A2'),(1,'A(n)');
select mm.machineid,ms.selection,ii.upc,ii.name
from machine_setup ms
join machine_machine mm
on mm.id=ms.machine_id
join item_item ii
on ii.id=ms.machine_id;
+-------------+-----------+-------+----------+
| machineid | selection | upc | name |
+-------------+-----------+-------+----------+
| EE100034442 | A1 | 10001 | Snickers |
| EE100034442 | A2 | 10001 | Snickers |
| EE100034442 | A(n) | 10001 | Snickers |
+-------------+-----------+-------+----------+
I'm not quite sure I understand the question, but the sql you want is like;
Select machine1.machineid, setup.Selection, item.upc, item.name
From Machine_machine machine1 --Set alias for the table
Inner Join machine_setup setup on setup.machine_id = machine1.id --This looks like a link table to me
Inner Join item_item item on setup.item_id = item.id -- in your example this wouldn't link as item_id is 1 in the machine_setup
In your example the machine_setup item_id is set to 1, which means it wouldn't link to the item_item table. i'm assuming this is a mistake.
Let me know if you need more information.

MySQL Alter table, add column with unique random value

I have a table that I added a column called phone - the table also has an id set as a primary key that auto_increments. How can I insert a random value into the phone column, that won't be duplicated. The following UPDATE statement did insert random values, but not all of them unique. Also, I'm not sold I cast the phone field correctly either, but ran into issues when trying to set it as a int(11) w/ the ALTER TABLE command (mainly, it ran correctly, but when adding a row with a new phone number, the inserted value was translated into a different number).
UPDATE Ballot SET phone = FLOOR(50000000 * RAND()) + 1;
Table spec's
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| phone | varchar(11) | NO | | NULL | |
| age | tinyint(3) | NO | | NULL | |
| test | tinyint(4) | NO | | 0 | |
| note | varchar(100) | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
-- tbl_name: Table
-- column_name: Column
-- chars_str: String containing acceptable characters
-- n: Length of the random string
-- dummy_tbl: Not a parameter, leave as is!
UPDATE tbl_name SET column_name = (
SELECT GROUP_CONCAT(SUBSTRING(chars_str , 1+ FLOOR(RAND()*LENGTH(chars_str)) ,1) SEPARATOR '')
FROM (SELECT 1 /* UNION SELECT 2 ... UNION SELECT n */) AS dummy_tbl
);
-- Example
UPDATE tickets SET code = (
SELECT GROUP_CONCAT(SUBSTRING('123abcABC-_$#' , 1+ FLOOR(RAND()*LENGTH('123abcABC-_$#')) ,1) SEPARATOR '')
FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS dummy_tbl
);
Try this
UPDATE Ballot SET phone = FLOOR(50000000 * RAND()) * id;
I'd tackle this by generating a (temporary) table containing the numbers in the range you need, then looping through each record in the table you wish to supply with random numbers. Pick a random element from the temp table, update the table with that, and remove it from the temp table. Not beautiful, nor fast.. but easy to develop and easy to test.