combine 3 or more tables, deliberately without a joining condition - mysql

How do i join 3 or more tables in mysql as follows?
there is a column for each column of each table (except ID)
ID field values all go into the same ID field in the new table
an additional column is added called table the values of which is the source Table name
an autoincremented newID field is added
only one table contributes to each row, unrelated fields have null values
total number of rows is equal to the sum records from all tables
example with just two tables :
TableA: TableB
ID | fieldA ID | fieldB
----------------- -----------------
1 | valueA1 1 | valueB1
2 | valueA2 2 | valueB2
ResultTable:
newID | ID | table | fieldA | fieldB
---------------------------------------------
1 | 1 | TableA | valueA1 |
2 | 2 | TableA | valueA2 |
3 | 1 | TableB | | valueB1
4 | 2 | TableB | | valueB2
I know this probably sounds a bit weird!. I am going to try and use this to batch insert nodes for records from various tables into neojs graph database with this batch-insert script. which could be hilarious considering I hardly know what I am doing in either database ;-) .

Try this one,
SELECT #rownum := #rownum + 1 AS NewID,
a.*
FROM
(
SELECT ID, fieldA, '' AS fieldB
FROM tableA
UNION ALL
SELECT ID, '' AS fieldA, fieldB
FROM tableB
) a, (SELECT #rownum:=0) r
SQLFiddle Demo
Create New Table
here's the proposed schema
CREATE TABLE Newtable
(
NewID INT AUTO_INCREMENT,
ID INT NOT NULL,
FieldA VARCHAR(30),
FieldB Varchar(30),
CONSTRAINT tb_pk PRIMARY KEY (NewID)
)
then Insert your values,
here's the query using INSERT INTO...SELECT statement
INSERT INTO NewTable (ID, fieldA, fieldB)
SELECT ID, fieldA, NULL AS fieldB
FROM tableA
UNION ALL
SELECT ID, NULL AS fieldA, fieldB
FROM tableB

Create a table with auto increment newID
Add all the possible columns allowing nulls.
INSERT INTO it the values from TableA, then TableB with something like:
INSERT INTO table
(ID, `table`, fieldA)
SELECT ID, 'TableA', fieldA FROM TableA
INSERT INTO table
(ID, `table`, fieldB)
SELECT ID, 'TableB', fieldB FROM TableB

Use UNION to select all rows in one result set, INSERT INTO for inserting to new table.
Also you can get new ID using ROW_NUMBER() in sql server
SELECT ID, COL1, NULL, NULL FROM Table1
UNION
SELECT ID, NULL, COL2, NULL FROM Table2
UNION
SELECT ID, NULL, NULL, COL3 FROM Table3
Select above result to a temp table. Use row number to update new ID
SELECT ID, ... , ROW_NUMBER() OVER(ORDER BY ID) AS NewID FROM #TempTable

Related

Delete from database where one part of a two part primary key has duplicates

This question stumps me. I have a database with a table that has a primary key that consists of two fields. In the end I require that the primary key only be one field, but I need to delete the duplicate entries from the table.
In other words the table has:
PRIMARY KEY (`field1`, `field2`)
There are entries that have duplicate field1 and different field2. So I have entries like this:
field1 | field2
1 | 1
1 | 2
2 | 1
2 | 2
3 | 1
4 | 1
I want to delete 1 of each of those entries that have duplicates on field1.
How can I do this with MySQL / SQL?
I think this will work in your case,
DELETE t1 FROM table t1
INNER JOIN table t2
WHERE t1.id > t2.id
AND t1.field1 = t2.field1
In this query I am joining the same table and picking duplicate values of field1 with different id and removing those.
Hope this works!!
I dont know how the delete from table needs to be specified in the mysql syntax but essentially you are trying to remove the second entry for the field1 for each of its unique value. So in some way if you are able to retrieve those records and pass them as select statements under your delete from table clause it should work.
For instance, here is the query that would select 2nd row for each value of field1 if it is repeated
select field1, field2
from
(
select *, count(*) over (partition by field1) as ct
, rank() over (partition by field1 order by field2 desc) as rn
from temp
) where rn = 1 and ct = 2
In your case it would return below records
field1 field2
1 2
2 2
So then all you need to do is have a delete from table clause at the top of that select statement.
NOTE - I have tried a solution without a join and hence I maintain these 2 analytical functions.
For instance this works in something like BigQuery -
delete from TABLE where concat(field1, field2) in
(
select concat(field1, field2)
from
(
select *, count(*) over (partition by field1) as ct
, rank() over (partition by field1 order by field2 desc) as rn
from TABLE
) where rn = 1 and ct = 2
)

Add values to table1 for each element from table2 and using MAX(id) + 1 from table1 as table2 id

I have table1 and table2 and want to do something like the following:
INSERT INTO table1 (ID, OWNER_ID, NAME) SELECT (SELECT MAX(ID) FROM table1) + 1, ID, 'value' FROM table2
The query above does not work and returns:
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.table1(ID)"; SQL statement:
Any help please?
table1:
| ID | OWNER_ID | NAME |
| --- | ---- | --- |
ŧable2:
| ID | OWNER_ID_REF | NAME |
| --- | ---- | --- |
Thanks
set #i:=(SELECT MAX(ID) FROM table1);
INSERT INTO table1 (ID, OWNER_ID, NAME) SELECT #i:=#i+1, ID, 'value' FROM table2
try this query it will work fine
It looks like ID is a primary key column in table1. Your current insert will most likely be inserting the same ID value multiple times, because the max subquery will have the same value for each record in table2. Assuming ID is auto increment, you probably should not be assigning a value to it anyway. Here is one option:
INSERT INTO table1 (OWNER_ID, NAME)
SELECT ID, 'value'
FROM table2;
You are using
SELECT (SELECT MAX(ID) FROM table1) + 1, ID, 'value' FROM table2
When you are inserting Through select
Max(ID)+1
give sample value all the records for table2
Use something like this...
Create table #tt( id int primary key ,Name varchar(200))
declare #vaue int = (select max(id) from #tt)
insert into #tt
select row_number() over(order by id) + #vaue
,Name from #tt

Mysql insert a row only if id exist in another table

I have 2 simple table
table1 -> p_id | s_id
table2 -> p_id | s_id
The two table are same. The p_id ai value.
I would like to insert into the table2 a row, but **only if p_id is exist in table1. This is possible? (MySQL)
INSERT INTO table1 (p_id, s_id)
SELECT * FROM (SELECT '100', '2') AS tmp
WHERE NOT EXISTS (SELECT p_id FROM table2 WHERE p_id = '100')
LIMIT 1
You can insert into a table based on any SELECT query. For example:
INSERT INTO table2 (p_id, s_id)
SELECT p_id, 2 FROM table1 WHERE p_id = 100;
If there are zero rows in table1 with the specified p_id value, this is a no-op. That is, it inserts zero rows into table2. If there is 1 row in table1 with that p_id value, it inserts into table2.
No need for LIMIT 1 because if p_id is the primary key then there is guaranteed to be only 1 or 0 rows with the given value.
Try This
Insert into table2 (p_id,s_id) Select p_id,'2' as s_id FROM table1 where p_id=100 LIMIT 1

SQL: Get at least the Third Largest Value from a set of columns of a row

I need a single SQL query to get the second largest value from a set of columns of a row.
For example, if these are my table's rows:
id | col1 | col2 | col3 | col4 | coln |
1 | 5 | 7 | 9 | 3 | 10 |
2 | 13 | 14 | 2 | 54 | 11 |
For rowid 1 - I need the value 9,
rowid 2 - I need the value 14
I'm afraid that, without common table expressions and/or window functions and without resorting to writing a procedure, this gets horribly verbose in MySQL
SELECT t.id, t.val second_largest
-- unpivot your columns into a table
FROM (
SELECT id, col1 val FROM my_table UNION ALL
SELECT id, col2 FROM my_table UNION ALL
SELECT id, col3 FROM my_table UNION ALL
SELECT id, col4 FROM my_table UNION ALL
SELECT id, coln FROM my_table
) t
-- retain only those records, where there exists exactly one record with a
-- column value greater than any other column value with the same id
WHERE 1 = (
SELECT COUNT(*)
-- Here, use unions to be sure that every value appears exactly once
FROM (
SELECT id, col1 val FROM my_table UNION
SELECT id, col2 FROM my_table UNION
SELECT id, col3 FROM my_table UNION
SELECT id, col4 FROM my_table UNION
SELECT id, coln FROM my_table
) u
WHERE t.id = u.id
AND t.val < u.val
)
Here's the SQLFiddle to check it (thanks to bluefeet for the heads-up with the schema!). The above solution will find the second largest column value in every row, even if the largest column value appears more than once.
You could do this by unpivoting the data and then applying a row number to each record in the id group. The unpivot takes the data from the column layout and places it into rows so it is easier to determine the second highest value:
select id, col, value
from
(
-- assign a group row number to each record
select *,
#row:=(case when #prev=id and #prevvalue<>value then #row else 0 end) + 1 as rownum,
#prevvalue:=value,
#prev:=id pid
from
(
-- unpivot the multi columns into row values
select id, 'col1' col, col1 value
from yourtable
union all
select id, 'col2' col, col2 value
from yourtable
union all
select id, 'col3' col, col3 value
from yourtable
union all
select id, 'col4' col, col4 value
from yourtable
union all
select id, 'coln' col, coln value
from yourtable
) src
order by id, value desc
) src
-- apply filter looking for the rownumber = 2 which is the second highest based on order
where rownum = 2
See SQL Fiddle with Demo
The result will show:
| ID | COL | VALUE |
---------------------
| 1 | col3 | 9 |
| 2 | col2 | 14 |
SELECT MAX(col) FROM table WHERE col NOT IN (SELECT MAX(col) FROM table);
This gives you the second largest integer value in a specific column.
EDIT:
then just swap the rows with the columns before doing that. But if the columns are dynamic, it could be quite tricky.
The best/easiest way would be to use a client side language and not SQL directly for this specific operation. If not possible, check this: Transpose rows and columns without aggregate

How can disjoint columns be selected in a single query?

I have 4 tables each with different columns but they all have one column in common. This is an integer identifier column. So I will have some integer x, and I want all the rows from all 4 tables that have this one id column equal to x.
I've tried something similar to:
SELECT table1.col1, table2.col2 FROM table1 LEFT JOIN table2 ON table1.id=x OR coastlinessports.id=x
And I get back rows which have both the columns from both tables in the same row.
So one result block would have:
table1.col1, table2.col2
But I really want:
table1.col1
tale2.col2
Is there a way I can do this without doing 4 select queries in a row?
If you want sequential rows from different tables, and for each table to return a different number of rows, then you can use UNION. However, UNION requires each SELECT to return the same number of columns, so you will need to fill in the missing columns with a value (or NULL), like this:
DROP TABLE IF EXISTS `table1`;
DROP TABLE IF EXISTS `table2`;
CREATE TABLE `table1` (
`id` int(11) NOT NULL auto_increment,
`col1` VARCHAR(255),
`col2` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `table2` (
`id` int(11) NOT NULL auto_increment,
`col1` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO `table1` VALUES
(1, '1,1', '1,2'),
(2, '2,1', '2,2');
INSERT INTO `table2` VALUES
(1, '1,1'),
(2, '2,1');
SELECT `id`, `col1`, `col2` FROM `table1` WHERE `id` = 1
UNION
SELECT `id`, `col1`, NULL AS `col2` FROM `table2` WHERE `id` = 1;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | 1,1 | 1,2 |
| 1 | 1,1 | NULL |
+----+------+------+
If you want to further process the UNION result set, you can wrap it in another SELECT, like this:
SELECT `col1`, `col2` FROM (
SELECT `id`, `col1`, `col2` FROM `table1` WHERE `id` = 1
UNION
SELECT `id`, `col1`, NULL AS `col2` FROM `table2` WHERE `id` = 1
) AS `t1`
ORDER BY col2;
+------+------+
| col1 | col2 |
+------+------+
| 1,1 | NULL |
| 1,1 | 1,2 |
+------+------+
Is that what you are after?
This probably won't answer your question, but there's something weird about the JOIN.
Usually the "ON" condition refers to both tables being joined, similar to this:
... FROM table1 LEFT JOIN table2 ON table1.id = table2.id ...
I guess there can be cases where you wouldn't do that, but I can't think of any.
You should check out this post. It seems like what you are asking for:
http://ask.sqlteam.com/questions/870/pivoting-multiple-rows-into-one-row-with-multiple-columns
If the table is called the same you can use USING
And for the part of the given value, use WHERE
select * from table1 join table2 using(commonColumn) join table3 using(commonColumn) join table4 using(commonColumn) where commonColumn="desiredValue"
Update: on a second read of your question
You want this?
All rows of table1 where commonColumn="desiredValue"
Followed by
All rows of table2 where commonColumn="desiredValue"
Followed by
All rows of table3 where commonColumn="desiredValue"
Followed by
All rows of table4 where commonColumn="desiredValue"
If that's so, you need to use a UNION (and you have to make 4 selects)
IF the number of columns differs, you need to fill the gaps whit aliases
SELECT col1, col2, col3, col4 from table1 where commonColumn="desiredValue"
UNION
SELECT col1, col2, 0 as col3, 0 as col4 from table2 where commonColumn="desiredValue"
...