SQL: Select Insert using ID from first Column - mysql

So I'm in a situation where I currently have two tables, that are linked by some foreign key.
`table_a` (
`table_id` int not null,
`important_value varchar(128) not null,
);
`table_b` (
`table_id` int not null,
`table_a_id` int not null,
)
I want to move important_value into table_b, which has a reference to table_a.
Assuming that I use the following alter SQL
alter table `table_b` add column `important_value` varchar(128) not null;
How would I now insert the relevant important_value into table_b given it has reference to table_a_id?

You can use a join:
update table_b b join
table_a a
on b.table_a_id = a.table_id
set b.important_value = a.important_value;

Related

mysql dependent subquery stops working when using a constant

Using MySQL 5.7.17-log
We have a number of report queries using a dependent subquery in the select statement that is returning null when there should be a value. I know this style can be refactored into a left join but I wanted to understand the reason we are having this problem and possibly file a bug with MySQL. Here is the simplest way to reproduce this:
CREATE TABLE tableA (
id varchar(36) NOT NULL,
col2 int(10) unsigned zerofill NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
;
CREATE TABLE tableB (
id varchar(36) NOT NULL,
col2 int(10) unsigned zerofill NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE tableC (
refA varchar(36) NOT NULL,
refB varchar(36) NOT NULL,
PRIMARY KEY (refA, refB),
CONSTRAINT fkCA FOREIGN KEY (refA) REFERENCES tableA (id),
CONSTRAINT fkCB FOREIGN KEY (refB) REFERENCES tableB (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE tableD (
refA varchar(36) NOT NULL,
refB varchar(36) NOT NULL,
col3 int(10) unsigned zerofill NOT NULL,
PRIMARY KEY (refA, refB),
CONSTRAINT fkDA FOREIGN KEY (refA) REFERENCES tableA (id),
CONSTRAINT fkDB FOREIGN KEY (refB) REFERENCES tableB (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
insert into tableA values ('123',5)
;
insert into tableB values ('234',6)
;
insert into tableC values ('123','234')
;
insert into tableD values ('123','234',7)
;
select a.id as 'aid',
b.id as 'bib',
( select d.col3 from tableD d where d.refA=a.id and d.refB=b.id ) as 'shouldBe7'
from tableA a
inner join tableC c on c.refA = a.id
inner join tableB b on c.refB = b.id
where a.id='123'
group by a.id, b.id
;
The select statement produces ['123','234',null] although I would expect ['123','234',7]. If you remove the where clause in the statement (where a.id='123'), the expected result - ['123','234',7] is what you get.
I did an explain on the whole select statement and saw that the "ref" uses a func which I did a SHOW WARNINGS and the dependent subquery is comparing the id against an empty string.
(/* select#2 */ select dev.d.col3 from dev.tableD d where ((dev.d.refA = '') and (dev.d.refB = dev.b.id))) AS shouldBe7
Seems like a 5.7 bug...I've filed http://bugs.mysql.com/87915 . the db-fiddle tool was helpful - thanks James!
This ran out of the box for me on 10.1.25-MariaDB locally:
Tried this 5.6 fiddle and it worked.
Tried this 5.7 fiddle and it also worked
I had a look at your code but couldn't see any obvious causes of this error, have you tried on other 5.7 instances to rule out any possible local causes?
Regards,
James
Try this instead...there's always more than one way to skin a cat.
select a.id as 'aid',
b.id as 'bib',
d.col3 as 'shouldBe7'
from tableA a
inner join tableC c on c.refA = a.id
inner join tableB b on c.refB = b.id
inner join ( select col3, refA, refB from tableD ) as d
on d.refA=a.id and d.refB=b.id
where a.id='123'
group by a.id, b.id
;

LEFT JOIN two tables so that left table data is filtered but right table data is displayed even if left table data does not exist

To allow our customers to store some of their own data along with our data structure I have created two extra tables:
CREATE TABLE external_columns
(
`id` INT(11) PRIMARY KEY NOT NULL,
`column` VARCHAR(30) NOT NULL,
`sid` INT(11) NOT NULL,
`bid` INT(11) NOT NULL,
`label` VARCHAR(30) NOT NULL,
`table` VARCHAR(30) NOT NULL,
`default` TINYTEXT NOT NULL
);
CREATE TABLE external_data
(
`id` INT(11) PRIMARY KEY NOT NULL,
`extcol_id` INT(11) NOT NULL,
`sid` INT(11) NOT NULL,
`bid` INT(11) NOT NULL,
`data` MEDIUMTEXT NOT NULL,
`row_id` INT(11) NOT NULL,
CONSTRAINT `external_data_external_columns_id_fk`
FOREIGN KEY (extcol_id) REFERENCES external_columns (id)
);
CREATE UNIQUE INDEX combinedUniqueIndex
ON external_data (extcol_id, sid, bid, row_id);
sid and bid are system values that identify the customer the data belongs to. row_id refers to the primary key of table referenced in table.
To get data for a certain row I have created this prepared statement:
SELECT `data`.*, `columns`.`column`, `columns`.`default`
FROM `external_columns` as `columns`
LEFT JOIN `external_data` as `data`
ON `columns`.`id` = `data`.`extcol_id`
WHERE (
`columns`.`sid` = :sid
AND `columns`.`bid` = :bid
AND `data`.`row_id` = :row_id
AND `columns`.`table` = :tableName
)
This works fine as long as for each external_column there is an entry in external_data for the given :row_id. But I want to make sure that there is always a row for each column, even if there is no data for the given :row_id. Is there a way to do this with one query?
Very close, by placing AND data.row_id = :row_id in your WHERE, you have effectively written an INNER JOIN as nulled data.row_ids won't match.
You should move this condition to the LEFT JOIN conditions:
SELECT `data`.*, `columns`.`column`, `columns`.`default`
FROM `external_columns` as `columns`
LEFT JOIN `external_data` as `data`
ON `data`.`extcol_id`= `columns`.id
AND `data`.`row_id` = :row_id
WHERE `columns`.`sid` = :sid
AND `columns`.`bid` = :bid
AND `columns`.`table` = :tableName
Personal Preferences:
Don't need the WHERE parentheses and I always tend to put the table conditions for a JOIN in the JOIN conditions where applicable and JOIN table on the LHS to make indexing options more obvious..
No difference for INNER JOINs but essential for certain LEFT JOINs.

MySQL update a table and select from the same table in a subquery

I have table of link
CREATE TABLE `linktable` (
`id ` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`idParent` BIGINT(20) UNSIGNED NOT NULL,
`Role` ENUM('Contacts','Expert','...') NULL DEFAULT NULL,
`idChild` BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (`idt`),
UNIQUE INDEX `UK_Parent_Child_Role` (`idParent`, `idChild`, `Role`)
)
I want to update this table and don’t break the unique key.
With other database I make something like this :
Update linktable lt1 Set lt1.Parent = :ziNew Where lt1.idParent = :ziOld
and not exists (select * from linktable lt2 where lt2.idParent = :ziNew and lt1.role = lt2.role and lt1.idChild = lt2.idChild);
How to make this with MySQL ?
Using your same syntax for variables, you would do this with a join:
Update linktable lt1 left outer join
(select *
from linktable lt2
where lt2.idParent = :ziNew
) lt2
on lt1.role = lt2.role and lt1.idChild = lt2.idChild
Set lt1.Parent = :ziNew
Where lt1.Parent =:ziOld and lt2.idParent is null;
The problem in MySQL is that the subquery is one the same table as the updated table. If it were a different table, then the original form with not exists would still work.

select multiple rows from tow tables mysql

I'm trying to select mltiple rows from tow table :
first table is donor
CREATE TABLE donor(
donor_number INT NOT NULL AUTO_INCREMENT,
d_name VARCHAR(30) NOT NULL,
mobile_number INT NOT NULL,
blood_group VARCHAR(20) NULL,
dob DATE NOT NULL,
gender ENUM('male','female') NOT NULL,
govid INT(10) NOT NULL,
PRIMARY KEY (donor_number )
);
second table is blood_donation
CREATE TABLE blood_donation(
donor_number INT NOT NULL,
date_of_donate DATE NOT NULL,
blood_group VARCHAR(20) NULL,
serial_number INT(10) NOT NULL,
blood_component ENUM('wb','prcb') NOT NULL,
PRIMARY KEY (donor_number , date_of_donate ),
FOREIGN KEY (donor_number) REFERENCES donor(donor_number)
);
with this select statement:
SELECT
serial_number,
blood_group
FROM blood_donation
WHERE date_of_donate = '2012-07-18'
UNION ALL
SELECT
blood_group
FROM donor
WHERE donor.donor_number=blood_donation.donor_number;
but, I get error
SQL state 42S22: Unknown column 'blood_donation.donor_number' in 'where clause'
any idea????
Actually you should not be using UNION but JOIN :)
you query will look like this
SELECT
blood_donation.serial_number,
donor.blood_group
FROM
blood_donation ,
donor
WHERE donor.donor_number = blood_donation.donor_number AND date_of_donate = '2012-07-18' ;
A UNION is used to combine more than one result set into a single result set - and each result set must have the same set of columns.
What you need is a JOIN, which is how you link multiple tables together on foreign keys etc and would be something like this:
SELECT
serial_number,
blood_group
FROM blood_donation
INNER JOIN donor ON donor.donor_number=blood_donation.donor_number
WHERE date_of_donate = '2012-07-18'
SELECT
dd.serial_number,
dd.blood_group
FROM blood_donation dd
inner join
donor d
on d.donor_number=dd.donor_number
WHERE dd.date_of_donate = '2012-07-18';
UNION is not what exactly you need, Read some more about JOINS. Also please change the selection alias of columns as per the need. And you can use Left Join instead of Inner Join if you don't want a mandatory join condition on tables.

mysql left join question

I want make query select all names from table 'a' where from table 'b' i have id_one='3'. id_two is id record from table
'a', two records have relation from id_one='3'. How i can make query ?
CREATE TABLE IF NOT EXISTS `a` (
`id` int(11) NOT NULL,
`name` varchar(11) NOT NULL,
`value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Zrzut danych tabeli `a`
--
INSERT INTO `a` (`id`, `name`, `value`) VALUES
(1, 'lalala', 0),
(2, 'allalala', 0);
CREATE TABLE IF NOT EXISTS `b` (
`id_one` int(11) NOT NULL,
`id_two` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Zrzut danych tabeli `b`
--
INSERT INTO `b` (`id_one`, `id_two`) VALUES
(3, 1),
(3, 2);
This is what you want:
select Name
from a inner join b on a.id = b.id_two
where b.id_one = 3
sorry I'm not fully understanding your schemas or your question, but I think what you're trying to ask for is:
SELECT * FROM a
JOIN b on a.id = b.id_two;
Try that.
Your question title mentions left joins, but you don't need a left join to make the query you described.
Left joins are good for finding things that don't match up the way you'd expect. So, using a left join in this case depends on what you are looking for. If you are looking for b.id_two entries that don't have corresponding table a entries,
select Name, b.* from b left join a on a.id = b.id_two
This will give you a table that lists every row in table b, with NULLs in place of the names for table a where there is no match.
Likewise, if you are looking for names that don't have entries in b.id_two, you would use
select Name, b.* from a left join b on a.id = b.id_two
If you want to enforce that there is always a correspondence, you can define a foreign key constraint between the parent and child table.
select Name
from a join b on a.id = b.id_two
where b.id_one = 3;
Will also work to get your answer. Might I also suggest you significantly improve your create table statements to include indexing. E.G.
CREATE TABLE IF NOT EXISTS `a` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(11) NOT NULL,
`value` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `b` (
`id_one` bigint(20) NOT NULL,
`id_two` bigint(20) NOT NULL,
KEY `FKCAFBB09382DEAC` (`id_one`),
CONSTRAINT `b_a_1` FOREIGN KEY (`id_two`) REFERENCES `a` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I would also use bigint for primary keys and use charset=utf8
these days it is just to common to want to migrate application to multi-lingual, lay the ground work now. IMHO