mysql - union with creating demarcated field - mysql

I need UNION two tables with creating new field, where 1 for first table, and 2 for second.
I tried
(
SELECT field, 1 AS tmp
FROM table1
)
UNION
(
SELECT field, 2 AS tmp
FROM table2
)
But in result, tmp field was full of "1".
How it can be implemented?

Your query should work fine. The only thing you should change is UNION should be UNION ALL to give better performance. Without the ALL it defaults to UNION DISTINCT which causes the rows to be compared for duplicates*, but the way you have constructed them guarantees that there cannot be duplicates so this extra check is a waste of time. Here is some test code I used to verify that what you are doing ought to work:
CREATE TABLE table1 (field NVARCHAR(100) NOT NULL);
INSERT INTO table1 (field) VALUES
('foo1'),
('bar1'),
('baz1');
CREATE TABLE table2 (field NVARCHAR(100) NOT NULL);
INSERT INTO table2 (field) VALUES
('foo2'),
('bar2'),
('baz2');
SELECT field, 1 AS tmp
FROM table1
UNION ALL
SELECT field, 2 AS tmp
FROM table2
Result:
'foo1', 1
'bar1', 1
'baz1', 1
'foo2', 2
'bar2', 2
'baz2', 2
If you only get rows where tmp was equal to 1, maybe your table2 was empty?
*See the documentation for UNION.
The default behavior for UNION is that duplicate rows are removed from the result. The optional DISTINCT keyword has no effect other than the default because it also specifies duplicate-row removal. With the optional ALL keyword, duplicate-row removal does not occur and the result includes all matching rows from all the SELECT statements.

You are very close
Create YourNewTable
SELECT field, 1 AS tmp
FROM table1
UNION ALL
SELECT field, 2 AS tmp
FROM table2

Related

Prevent auto-increment on MySQL duplicate insert with multiple values

Is there an accepted practice for bulk inserting values that don't exist into a table without auto-incrementing when you attempt to insert a row that already exists?
There's a great answer for the single-row insert case at:
Prevent auto increment on MySQL duplicate insert
However, for insertion efficiency I'd like to insert a large number of rows with a single SQL command. (i.e.:INSERT INTO myBigTable VALUES ((value1_row1,value2_row1),(value1_row2,value2_row2) ... )
ADDITIONAL INFO:
I would like to have all the ID's available, since my table has the potential of becoming extremely large. Changing the auto_increment variable size to a BIGINT would be a last resort. My insertion application will attempt to insert a large number of already-existing rows on a regular basis (think stock price updates), so I'll effectively have a large number of auto-incremented ID's skipped.
WHY I'M USING AUTO-INCREMENT:
I believe that for query speed, I should be using an integer index into my (very large) table as the primary key instead of a combination of string fields. I also believe that I should use auto_increment, so MySQL handles concurrency for me.
You can use the technique in the other question, using a UNION query:
INSERT INTO yourTable (col1, col2, ...)
SELECT $row1_value1, $row1_value2, ...
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM yourTable
WHERE unique_col = $row1_value1)
UNION ALL
SELECT $row2_value1, $row2_value2, ...
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM yourTable
WHERE unique_col = $row2_value1)
UNION ALL
SELECT $row3_value1, $row3_value2, ...
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM yourTable
WHERE unique_col = row1_value1)
UNION ALL
SELECT $row4_value1, $row4_value2, ...
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM yourTable
WHERE unique_col = $row4_value1)

Compare large MySQL tables

I need to make a comparison between two (or more) tables with around 60.000 rows and about 60 columns.
In these tables there are two values on which I want to run a query. The purpose of the query is to count the rows which exists in TABLE_A but don't exist in TABLE_B based on two values in the row.
I've ran the following query:
SELECT id
FROM table_a ta
WHERE NOT EXISTS (
SELECT id
FROM table_b tb
WHERE ta.value1=tb.value1 AND ta.value2=tb.value2
)
As said, I've tried the code above and some variations on it. But to run this query it takes ages before it's finished. I hope to find a solution which runs in under 10 seconds.
Next query I tried, and of which I thought was working:
SELECT value1, value2
FROM (
SELECT ta.value1, ta.value2
FROM table_a ta
UNION ALL
SELECT tb.value1, tb.value2
FROM table_b tb
) result
GROUP BY value1, value2
HAVING COUNT(*) = 1
ORDER BY value1
The code shows me all differences between the two tables. So if valueX exists in TABLE_A but not in TABLE_B it's shown and vice versa.
So in short, I want to get all rows from TABLE_A which are not present in TABLE_B based on two values in the row.
Hope someone can help, thanks!
Why not use a join?
/* Create a table called NAMES */
CREATE TABLE NAMES(Id integer PRIMARY KEY, Name text, LastName text);
CREATE TABLE OTHERNAMES(Id integer PRIMARY KEY, Name text, LastName text);
/* Create few records in this table */
INSERT INTO NAMES VALUES(1,'Tom','Riddle');
INSERT INTO NAMES VALUES(2,'Lucy','I love');
INSERT INTO NAMES VALUES(3,'Frank','Frankly');
INSERT INTO NAMES VALUES(4,'Jane','Austen');
INSERT INTO NAMES VALUES(5,'Robert','Downey');
INSERT INTO OTHERNAMES VALUES(2,'Lucy','I love');
INSERT INTO OTHERNAMES VALUES(3,'Frank','Frankly');
INSERT INTO OTHERNAMES VALUES(4,'Jane','Austen');
INSERT INTO OTHERNAMES VALUES(5,'Robert','Downey');
select * from NAMES
LEFT JOIN OTHERNAMES on
NAMES.Name = OTHERNAMES.Name
AND Names.LastName = OTHERNAMES.LastName
where OTHERNAMES.id is null
See it online http://sqlfiddle.com/#!9/640c53/1
If you use a LEFT JOIN Items that don't exist in the right table will be replaced with null entries, which can be filtered with a where.
I don't know how efficient that is with your 60.000 database but this usually does the trick for me.
After some trial and error I have improved the second block of code. I noticed an additional field in my table which I could use to further filter the results.
SELECT date, value1, value2
FROM (
SELECT date, value1, value2
FROM (
SELECT ta.date, ta.value1, ta.value2
FROM table_1 ta
UNION ALL
SELECT tb.date, tb.value1, tb.value2
FROM table_2 tb
) filter
GROUP BY value1, value2
HAVING COUNT(*) = 1
) result
WHERE date='YYYY-MM-DD'
This code filters the results in under 4 seconds.
Anyway, thanks everyone for the trouble.

How can I copy table records unrepeatedly?

I have a table that contains some duplicate redords. I want to make records unique. I created a new table (say, destination) and I specified a unique column in it. How can copy records from table1 (source) such that, if the record inserted in the destination table, it does not insert it again.
You can use the "select into" construct and select insert only distinct rows, like this:
insert into table_without_dupes (column0, column1) select distinct column0, column1 from table_with_dupes
If you have autoincrement or other columns that makes the rows distinct, you can just leave them out of the insert and select parts of the statement.
Edit:
If you want to detect duplicates by a single column, you can use group by:
insert into table_without_dupes (column0, column1) select column0, column1 from table_with_dupes group by column0
MySQL will allow you to refer non-aggregated columns in select, but remember that the documentation says "The server is free to choose any value from each group", if you want to select one specific row of the groups, you might find this example useful.
Generic approach
insert into destination(col1,col2)
select DISTINCT col1,col2 from source as s where not exists
(select * from destination as d where d.col1=s.col1)
Edited
insert into destination(col1,col2)
SELECT distinct col1,col2 from source
Edited (Assuming col3 is duplicated and you want only one copy of it.)
insert into destination(col1,col2,col3,....,colN)
SELECT col1,col2,col3,...,colN from source as s1 inner join
(
select col1,col2,max(col3) as col3
from source
group by col1,col2
) as s2 on t1.col1=t2.col1 and t1.col2=t2.col2 and t1.col3=t2.col3
insert into <dest_table_name>
select distinct * from <source_table_name>;

INSERT INTO with SubQuery MySQL

I have this Statement:
INSERT INTO qa_costpriceslog (item_code, invoice_code, item_costprice)
VALUES (1, 2, (SELECT item_costprice FROM qa_items WHERE item_code = 1));
I'm trying to insert a value copy the same data of item_costprice, but show me the error:
Error Code: 1136. Column count doesn't match value count at row 1
How i can solve this?
Use numeric literals with aliases inside a SELECT statement. No () are necessary around the SELECT component.
INSERT INTO qa_costpriceslog (item_code, invoice_code, item_costprice)
SELECT
/* Literal number values with column aliases */
1 AS item_code,
2 AS invoice_code,
item_costprice
FROM qa_items
WHERE item_code = 1;
Note that in context of an INSERT INTO...SELECT, the aliases are not actually necessary and you can just SELECT 1, 2, item_costprice, but in a normal SELECT you'll need the aliases to access the columns returned.
You can just simply e.g.
INSERT INTO modulesToSections (fk_moduleId, fk_sectionId, `order`) VALUES
((SELECT id FROM modules WHERE title="Top bar"),0,-100);
I was disappointed at the "all or nothing" answers. I needed (again) to INSERT some data and SELECT an id from an existing table.
INSERT INTO table1 (id_table2, name) VALUES ((SELECT id FROM table2 LIMIT 1), 'Example');
The sub-select on an INSERT query should use parenthesis in addition to the comma as deliminators.
For those having trouble with using a SELECT within an INSERT I recommend testing your SELECT independently first and ensuring that the correct number of columns match for both queries.
Your insert statement contains too many columns on the left-hand side or not enough columns on the right hand side. The part before the VALUES has 7 columns listed, but the second part after VALUES only has 3 columns returned: 1, 2, then the sub-query only returns 1 column.
EDIT: Well, it did before someone modified the query....
As a sidenote to the good answer of Michael Berkowski:
You can also dynamically add fields (or have them prepared if you're working with php skripts) like so:
INSERT INTO table_a(col1, col2, col3)
SELECT
col1,
col2,
CURRENT_TIMESTAMP()
FROM table_B
WHERE b.col1 = a.col1;
If you need to transfer without adding new data, you can use NULL as a placeholder.
If you have multiple string values you want to add, you can put them into a temporary table and then cross join it with the value you want.
-- Create temp table
CREATE TEMPORARY TABLE NewStrings (
NewString VARCHAR(50)
);
-- Populate temp table
INSERT INTO NewStrings (NewString) VALUES ('Hello'), ('World'), ('Hi');
-- Insert desired rows into permanent table
INSERT INTO PermanentTable (OtherID, NewString)
WITH OtherSelect AS (
SELECT OtherID AS OtherID FROM OtherTable WHERE OtherName = 'Other Name'
)
SELECT os.OtherID, ns.NewString
FROM OtherSelect os, NewStrings ns;
This way, you only have to define the strings in one place, and you only have to do the query in one place. If you used subqueries like I initially did and like Elendurwen and John suggest, you have to type the subquery into every row. But using temporary tables and a CTE in this way, you can write the query only once.

mysql insert value if it doesn't exist

I'm trying to insert an ingredient to an ingredients table if it doesn't exist.
I'm using the following syntax:
INSERT INTO ingredient(Name)
(
SELECT 'ingName' FROM dummytable WHERE
(SELECT count(*) FROM ingredient WHERE Name = 'ingName')=0)
This does not seem to work (0 rows affected), even though the SELECT query seem to return the desired result (an entry which contains "ingName").
The "ingredient" table has 2 columns: Name, id (id is auto incremented)
Thanks,
Li
Its better to add unique index on the name column:
ALTER TABLE `ingredient` ADD UNIQUE(`Name`)
After doing that you can use INSERT IGNORE:
INSERT IGNORE INTO `ingredient` ... /* anything */
That's because your inner query SELECT count(*) FROM ingredient WHERE Name = 'ingName' is returning a value > 0 and hence the upper query SELECT 'ingName' FROM dummytable WHERE is not selecting any rows and so no insert is happening.
I tried the same with a test table having 2 column name|value and it did worked fine
INSERT INTO test1(name) (
SELECT 'name' FROM test2 WHERE
(
SELECT count(*) FROM test2 WHERE name = 'bilboa'
)
=0
)
Inserted 2 rows with value name cause that's what I am selecting in select query and my test table 2 rows.