TABLE 1
+----+-------+-------+-------+
| uid | color | brand | model |
+----+-------+-------+-------+
| 10 | 1 | 2 | 1 |
+----+-------+-------+-------+
TABLE 2
+----+-------+-------+-------+
| uid | quantity |model |color|
+----+-------+-------+-------+
| 25 | 2 | 2 | 1 |
+----+-------+-------+-------+
I have many tables like this where the uid column is present in every table.I have a value in a variable, say var1=25. I want to check whether var1 value matches with any of the uid value of any table.If it matches I want to print the table name. Can anyone help me with this?
I tried doing this and I found
SELECT `COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`='yourdatabasename'
AND `TABLE_NAME`='yourtablename';
But this is not giving what I want since I want to select all the tables in a database irrespective of the table name.If in future any table is added then it should also get selected.
At first, information_schema table doesn't have specific tuple data.
I suggest you to consider different design.
A. Make a meta table and use triggers(attached to base tables) to maintain meta table.
CREATE TABLE meta_table (
id INT AUTO_INCREMENT,
uid INT,
table_name VARCHAR(50)
);
# When you need to add new table (table 3)
CREATE TABLE table_3 (
uid INT,
field1 INT,
field2 INT,
field3
);
DELIMITER $$
CREATE TRIGGER table_3_insert
AFTER INSERT ON table_3
FOR EACH ROW
BEGIN
INSERT INTO meta_table (uid, table_name)
VALUE (NEW.uid, "table_3");
END$$
DELIMITER ;
# If data in `table_3` might be changed or deleted,
# then create trigger for `delete` and `update`
B. Use only one table with unstructured field and parse data field in your application
CREATE TABLE table (
uid INT,
table_type INT,
data VARCHAR(255)
);
INSERT INTO table (10, 1, '{"color":1,"brand":2,"model":1}');
INSERT INTO table (10, 2, '{"quantity":2,"model":2,"color":1}');
As you mentioned "any table can be added" often, I strongly recommend B solution. It is not good design that changing schema(creating table) often.
Related
I've got a table with multiple duplicated entries in a column and I want to put these entries in a new table and connect these tables with a foreign key in the initial table.
Old Table:
table 1
| id | name | medium |
| 0 | xy | a |
| 1 | xz | b |
| 2 | yz | a |
new Table:
table 1 table2
| id | name | medium | | id | name |
| 0 | xy | 0 | | 0 | a |
| 1 | xz | 1 | | 1 | b |
| 2 | yz | 0 |
With CREATE ... SELECT I have a good tool to create a new table from the results of a query but I don't know how to change the entries from table1.medium to a foreign key based on the comparison to table2.medium. Is there any chance to do that?
You can do:
-- Create the second table
create table table2 (
id int primary key,
name varchar(255) unique
);
-- Insert rows into it
insert into table2
select row_number() over (order by medium), medium
from original
group by medium;
-- Use JOIN to create the first table and populate with the right ids
create table table1 as
select o.id, o.name, t2.id as medium
from original o join
table2 t2
on t2.medium = o.name;
Here is a db<>fiddle.
You can turn the id in table2 then into an auto_increment column:
alter table table2 modify column id int auto_increment;
It sounds like you can create Table2 but are having trouble changing Table1, updating the column type from char to int and creating a foreign key.
Easiest would be to rename Table1 to Table3 then create Table1 as you want, insert the data, then drop Table3.
If you need to modify the existing table, it will be a multi-step process.
Add new column 'medium_old' and copy existing values from medium
Drop the column 'medium' with the char type
Add the column 'medium' with the new int type
Update the new 'medium' values to the key from Table2 based on values in 'medium_old'
Add the foreign key constraint to 'medium'
There are two ways of doing it:
You recreate table1 with the new values in the medium column. Then you drop the old table1 and rename the new table. I would use this approach if medium column not only needs new values, but also needs to be converted to a new data type - this seems to be the case in the question. You already figured this approach out with create table ... as ...
Using multi-table update syntax, you can easily update a field in a table based on a field in another table. I would use this approach if you do not need to change the data type of the medium column. See this SO question on how to do this update.
If you are running mysql version 8.0 or above you can do below and use window function ROW_NUMBER.
Source
CREATE TABLE TABLE2
AS
SELECT ID,NAME(
SELECT ID, MEDIUM AS NAME,ROW_NUMBER()OVER(PARTITION BY MEDIUM ORDER BY ID) AS ROWW FROM TABLE1)
WHERE ROWW=1;
-- Adds a new column into your TABLE1 for MEDIUM's int values
ALTER TABLE TABLE1 ADD COLUMN MEDIUMINT INT;
-- Update MEDIUMINT according to your TABLE2 values.
UPDATE TABLE1 S1
JOIN TABLE2 S2 ON TABLE1.MEDIUM=S2.NAME
SET S1.MEDIUMINT=S2.ID;
-- Drops MEDIUM column from TABLE1
ALTER TABLE TABLE1 DROP COLUMN MEDIUM;
-- Rename MEDIUMINT column to MEDIUM
ALTER TABLE TABLE1 RENAME COLUMN MEDIUMINT TO MEDIUM;
I'm sorry if it's a silly question, but I don't know how to create dynamically an SQL Table.
Let's imagine that I have two tables :
Table1 : nameT1, numberT1, dateT1
The first one isn't dynamically initiated. BUT the second needs to be, and the values in it have different names. So I started with this approach :
CREATE TABLE Table2 (
nameT2 VARCHAR(20),
numberT2 INTEGER(5),
dateT2 DATETIME
) AS SELECT (
nameT1,
numberT1,
dateT1
) FROM Table1;
But I have some problems with the compilation. And I don't know where I define that (for Table2) :
nameT2 = nameT1
numberT2 = numberT1
dateT2 = dateT1
I simplified the problem, normally I have conditions to select which ones I want to insert from Table1 but that's not part of the problem.
A create as select will create the defined columns then append the selected columns. If you want to rename the columns drop the column definitions and use aliases. For example
DROP TABLE IF EXISTS T,T1;
CREATE TABLE T (nameT1 VARCHAR(3),numberT1 INT, dateT1 DATE);
INSERT INTO T VALUES ('AAA',10,'2020-05-15');
CREATE TABLE T1 AS SELECT
nameT1 AS NAMET2,
numberT1 AS NUMBERT2,
dateT1 AS DATET2
FROM T;
SELECT * FROM T1;
+--------+----------+------------+
| NAMET2 | NUMBERT2 | DATET2 |
+--------+----------+------------+
| AAA | 10 | 2020-05-15 |
+--------+----------+------------+
1 row in set (0.001 sec)
EDIT 2:
Original post caused more confusion over problem-solving, so I decided to explain the whole situation in details.
Let me clarify the whole situation...
I am working on an eCommerce CMS (Prestashop). Site owners mistakenly added all manufacturers (id, name, description) as categories.
I want to create proper structure for manufacturers table so we can correct this issue.
Let me explain the whole structure of ps_manufacturer_lang table which needs to be filled (it does not have any value in it).
Table ps_manufacturer_lang has four columns named:
1. id_manufacturer
2. id_lang
3. description
4. short_description
Here are the values that should be inserted:
1. id_manufacturer should be filled with values from ps_manufacturer table.
2. id_lang should be 1.
3. description should be filled with values from ps_category_lang table with specific WHERE clause.
4. short_description should be NULL.
Let's go to the queries:
1. This INSERT INTO query fills id_manufacturer and id_lang properly:INSERT INTO ps_manufacturer_lang (id_manufacturer, id_lang)
SELECT
id_manufacturer,
1
FROM ps_manufacturer
2. This INSERT INTO query fills description properly:
INSERT INTO ps_manufacturer_lang (description)
SELECT
description
FROM ps_category_lang
WHERE
id_lang='1'
AND id_category IN (
SELECT id_category FROM ps_category WHERE id_parent='241'
)
Now, the question is, how to do this? It is not possible two use ONE INSERT INTO query with TWO SELECT FROM syntaxes.
You have to use insert select statement to copy other tables data.
INSERT INTO ps_manufacturer_lang (description)
SELECT description
FROM ps_category_lang
"your specific where condition"
To avoid duplicate entry , you have to make primary key AUTO_INCREMENT or create trigger for this table
drop table if exists ps_manufacturer_lang,ps_manufacturer,ps_category_lang;
create table ps_manufacturer_lang
(id_manufacturer int primary key,
id_lang int,
description varchar(20),
short_description varchar(20));
create table ps_manufacturer
(id int);
create table ps_category_lang
(id int, description varchar(20), id_parent int);
insert into ps_manufacturer values (1),(2);
insert into ps_category_lang values
(1,'aaa',241),
(2,'bbb',241);
insert into ps_manufacturer_lang
select pm.id,1,pl.description,null
from ps_manufacturer pm
join ps_category_lang pl on pl.id = 1 and id_parent = 241;
select * from ps_manufacturer_lang;
+-----------------+---------+-------------+-------------------+
| id_manufacturer | id_lang | description | short_description |
+-----------------+---------+-------------+-------------------+
| 1 | 1 | aaa | NULL |
| 2 | 1 | aaa | NULL |
+-----------------+---------+-------------+-------------------+
2 rows in set (0.00 sec)
My database structure is like so:
Table 1: customers
| userid | username | password | email |
| 1 | bob | mypassword123 | bob#gmail.com |
Please note that 'userid' is a primary key in this table
Table 2: accountbalance
| userid | balance |
| 1 | 100 |
Please note that 'userid' in accountbalance table is a foreign key to the 'userid' field in customers table.
When a new account is created, I not only want a new row in customers to be created, but I want a corresponding row in accountbalance to be created to give a started value of 100 ($100) but the problem is how do I know what the userid is?
I thought about running a query to look for the id using the username and then doing an INSERT INTO statement in the accountbalance. Would that work? Can I get a general outline?
It depends what db you use. Mysql has LAST_INSERT_INSERT_ID() function which you can call after your insert (just call SELECT LAST_INSERT_INSERT_ID()) and you'll get the id of last inserted row (in case your id is defined as AUTO_INCREMENT). If you use postgres it allows you to perform insert returning id. Something like INSERT INTO customerts(...) VALUES(...) RETURNING userid.
But as you mentioned if your username is unique I would use select using this attribute after insert, because it is db independent.
you can use trigger of mysql
delimiter |
CREATE TRIGGER temp AFTER INSERT ON customers
FOR EACH ROW
BEGIN
INSERT INTO accountbalance SET userid = NEW.userid;
END;
|
delimiter ;
ref: https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
set default value of balance field in accountbalance table to 100 while creating table or edit later.
I am trying to copy a table from one database to another database.
Already there are several solutions for this problem. I use this method to solve this problem.
select *
into DbName.dbo.NewTable
from LinkedServer.DbName.dbo.OldTableSourceDB..MySourceTable
I have two databases. One is blog including a table named engineers; another database named msdata including a table named ms. I am trying to copy the table engineers to the database msdata. My query is:
select * into msdata.dbo.ms from linkedserver.blog.dbo.engineers;
but output is
Undeclared variable: msdata
I don't know it is the problem here. Any help will be appreciated.
Just an illustration:
create table so_gibberish.fred1
(
id int auto_increment primary key,
what varchar(40) not null
);
insert so_gibberish.fred1 (what) values ('this'),('that');
insert into newdb789.fred1 select * from so_gibberish.fred1;
-- failed, error code 1146: Table 'newdb789.fred1' doesn't exist
create table newdb789.fred1
(
id int auto_increment primary key,
what varchar(40) not null
);
insert into newdb789.fred1(id,what) select id,what from so_gibberish.fred1;
insert into newdb789.fred1 (what) values ('a new thing');
select * from newdb789.fred1;
+----+-------------+
| id | what |
+----+-------------+
| 1 | this |
| 2 | that |
| 3 | a new thing |
+----+-------------+
good, auto_increment preserved and resumes at 3 for new things
Try this alternative query below, make sure you have already created the table in destination database:
INSERT INTO DestinationDatabase..DestinationTable
SELECT * FROM SourceDatabase..SourceTable;