confusing MySqL JOIN - mysql

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);

Related

Create a view and don't let the database update mysql?

create table Branch
(
BranchNo char(4),
Street varchar(30),
City varchar(30),
PostCode varchar(10)
)
INSERT INTO BRANCH
VALUES ('B002', '55 cOVER', 'LONDON',NULL)
INSERT INTO BRANCH
VALUES ('B003', '163 Main Street', 'Glasgow',NULL)
INSERT INTO BRANCH
VALUES ('B004', '32 Manse Road', 'Bristol',NULL)
INSERT INTO BRANCH
VALUES ('B005', '22 Dear Road', 'LONDON',NULL)
INSERT INTO BRANCH
VALUES ('B007', '16 Argyll', 'Abend',NULL)
Create a view named ViewDeC that displays information of all branches. Must say
make sure it is not possible to update the data for the branch table (Branch) through this View
Create a view and don't let the database update mysql?
enter image description here
If I am not mistaken, this is about how to create a readonly view. Though MySQL does not support creating a view with readonly attribute DIRECTLY, certain things can be done to make the view READONLY. One workaround is to make the view through joined tables.
create view ViewDeC as
select BranchNo,Street,City,PostCode
from Branch
join (select 1) t;
select * from ViewDec;
INSERT INTO ViewDec
VALUES ('B009', '99 Argyll', 'bender',NULL);
-- Error Code: 1471. The target table ViewDec of the INSERT is not insertable-into
Note, this is implemented at the cost of some performance, but not terribly unbearable. I have a table with 1.4 million rows. Here is the test with and without join using a table scan as the access method.
select * from proctable;
-- 1429158 rows in set (1.26 sec)
select * from proctable join (select 1) t;
-- 1429158 rows in set (1.40 sec)
However, for an index lookup access method, this is almost non-existent.
select * from proctable join (select 1) t where id between 100 and 500;
-- 401 rows in set (0.00 sec)
explain select * from proctable join (select 1) t where id between 100 and 500;
+----+-------------+------------+------------+--------+---------------+---------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+---------+---------+------+------+----------+----------------+
| 1 | PRIMARY | <derived2> | NULL | system | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 1 | PRIMARY | proctable | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 401 | 100.00 | Using where |
| 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+------------+------------+--------+---------------+---------+---------+------+------+----------+----------------+

How to match value of a table to another and create a new column in mySQL?

I am new to SQL and have been stuck at this one part of my work/assg for a long time and would really appreciate some guide/input!
I have 2 tables. The first table has a codepath that corresponds to the ordercode in the second table, if it matches and the flag is INCL, I should have another column that puts the itemcode specified in table 2 into table 1 and if it's EXCL, i should not include it.
Table1:
| code | codepath |
|:---- |:------: |
| ABC12 | something/NPP3 |
| ABC13 | something/NPP4 |
Table2:
| itemcode | ordercode | flag |
|:---- |:------: |-----:|
| CASH | NPP3 | INCL |
| EXCASH | NPP4 | EXCL |
Result:
| code | codepath | tag |
|:---- |:------: | -----:|
| ABC12 | something/NPP3| CASH |
| ABC13 | something/NPP4| EXCASH |
There are many rows and this is just one example. Not sure if I should join the table but I dont think so as the number of rows dont match and there is no common column as well. Would greatly appreciate any help or guidance!
can you check this?
select t1.code, t1.codepath, t2.itemcode as tag
from
table1 t1 join table2 t2 on SUBSTRING_INDEX(t1.codepath, '/', -1) = t2.ordercode
You would do better to use codepath as the joining column.
It should therefore be indexed, I suggest as a foreign key.
You could join using concat or substring but it is better to avoid functions in joins and enforce consstency with foreign keys. Where possible it is better to use an integer for the primary key to speed up the table scans and indexing.
create table table2 (
itemcode varchar(10) primary key,
ordercode char(5) unique,
flag char(4) );
create table table1 (
code char(5) primary key,
codepath char(5) ,
foreign key fk_codeparth (codepath)
references table2(ordercode));
insert into table2 values
('CASH','NPP3','INCL'),('EXCASH','NPP4','EXCL');
insert into table1 values
('ABC12','NPP3'),('ABC13','NPP4');
select
t1.code,
t1.codepath,
t2.flag tag
from table1 t1
join table2 t2 on t1.codepath = t2.ordercode;
code | codepath | tag
:---- | :------- | :---
ABC12 | NPP3 | INCL
ABC13 | NPP4 | EXCL
*db<>fiddle here727c5a30c04725d5486acdc)

Inserting new data in a table

I have created a basic table for learning purposes.
CREATE TABLE friends (
id INT,
name TEXT,
birthday DATE
);
Added some data...
INSERT INTO friends (id,name,birthday)
VALUES (1,'Jo Monro','1948-05-30');
INSERT INTO friends (id,name,birthday)
VALUES (2, 'Lara Johnson','1970-03-03');
INSERT INTO friends (id,name,birthday)
VALUES (3,'Bob Parker', '1962-09-3');
And I realised that I forgot to include the email column.
I added the column...
ALTER TABLE friends
ADD COLUMN email;
..but how can I add now data to this new column only?
I have tried WHERE statements, rewriting the INSERT INTO statements with and without the other column names but nothing worked?
What am I missing here?
Thank you!
Insert the emails into a temporary table, then update the real table with that.
CREATE TABLE friends (
id INT auto_increment primary key,
name VARCHAR(100),
birthday DATE
);
INSERT INTO friends (name, birthday) VALUES
('Jo Monro','1948-05-30')
, ('Lara Johnson','1970-03-03')
, ('Bob Parker', '1962-09-3');
ALTER TABLE friends ADD COLUMN email VARCHAR(100);
select * from friends
id | name | birthday | email
-: | :----------- | :--------- | :----
1 | Jo Monro | 1948-05-30 | null
2 | Lara Johnson | 1970-03-03 | null
3 | Bob Parker | 1962-09-03 | null
--
-- temporary table for the emails
--
CREATE TEMPORARY TABLE tmpEmails (
name varchar(100) primary key,
email varchar(100)
);
--
-- fill the temp
--
insert into tmpEmails (name, email) values
('Jo Monro','jo.monro#unmail.net')
, ('Lara Johnson','lara.johnson#unmail.net')
, ('Bob Parker', 'UltimateLordOfDarkness#chuni.byo');
--
-- update the real table
--
update friends friend
join tmpEmails tmp
on friend.name = tmp.name
set friend.email = tmp.email
where friend.email is null;
select * from friends
id | name | birthday | email
-: | :----------- | :--------- | :-------------------------------
1 | Jo Monro | 1948-05-30 | jo.monro#unmail.net
2 | Lara Johnson | 1970-03-03 | lara.johnson#unmail.net
3 | Bob Parker | 1962-09-03 | UltimateLordOfDarkness#chuni.byo
db<>fiddle here

Updating SQL Query on multiple values

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"))

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.