Change database structure: need an SQL query - mysql

I have two tables:
connections
id | publisherId | authorId
and
books
id | connectionId | title
I want to merge these tables to get only one table:
books
id| publisherId | authorId | title
How can I do this with only one SQL query?

CREATE TABLE newtable
SELECT b.id, c.publisherId, c.authorID, b.title
FROM books b
INNER JOIN connections c
on c.id = b.connectionId
Untested, but this should do it. I assume you want the ID from the books table, otherwise you need c.id instead of b.id.
Then you can drop the old tables and rename this to whatever you want.

CREATE TABLE connections_books
SELECT books.id as id,
connections.publisherId as publisherId,
connections.authorId as authorId,
books.title as title
FROM books join connections on books.connectionId = connections.id;
Test the query first using just the select part:
SELECT books.id as id,
connections.publisherId as publisherId,
connections.authorId as authorId,
books.title as title
FROM books join connections on books.connectionId = connections.id;
Once this gives you what you want, go ahead and create the table.
It's important to make sure the column names in the new table are correct. Use the select statement testing to ensure your column names are what you want. If you want to change the column names, change the as ... names for each column selected.

Related

Selecting values from foreign tables

I'm working on the SELECT clause for the VALUES section of an SQL INSERT statement. One of the fields of the record is a foreign key to a table of foreign keys to other records.
Given:
Table - Ing_Fundamental
+----------------+-------------------+
| ID_Fundamental | ID_Title_Category |
+----------------+-------------------+
Table - Title_Category
+-------------------+----------+-------------+
| ID_Title_Category | ID_Title | ID_Category |
+-------------------+----------+-------------+
Table - Titles
+----------+-------+
| ID_Title | Title |
+----------+-------+
Table - Categories
+-------------+----------+
| ID_Category | Category |
+-------------+----------+
I want to select the ID_Title_Category field where Titles.Title = "Hamburger" and Categories.Category = "Meat".
My SQL INSERT statement:
INSERT INTO Ing_Fundamental
(
Ing_Fundamental.ID_Title_Category
)
VALUES
(
(SELECT ????)
)
Here's the SQL CREATE TABLE statement for Ing_Fundamental:
CREATE TABLE IF NOT EXISTS Ing_Fundamental
(
ID_Fundamental INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT NOT NULL,
ID_Title_Category INTEGER UNSIGNED,
FOREIGN KEY fk_ID_Title_Category(ID_Title_Category)
REFERENCES ing_title_categories(ID_Title_Category)
ON UPDATE CASCADE
ON DELETE RESTRICT,
UNIQUE(ID_Title_Category)
)
My attempt at the SELECT statement is:
(SELECT Ing_Title_Categories.ID_Title_Category
FROM Ing_Title_Categories
WHERE (ID_Title_Category = 0))
But the above statement isn't going to work correctly because the ID_Title_Category field value is not correct, it must be determined by looking up values in the Titles and Categories tables.
So, what is the SQL syntax for selecting the ID_Title_Category field based on the fields in the Titles and Categories tables?
Edit 1: background / design
A fundamental ingredient has a unique ID.
A fundamental ingredient has a title and a category.
Categories are fixed (limited).
A User wants to search the database for an ingredient based on a title and a category.
A recipe contains one or more ingredients (ingredient IDs).
I don't remember my justification for the Title_Category table; It could either be normalization or reduce the need for a compound primary key.
I'm writing an application in C++ to interact with the database via SQL statements and queries.
In programming terminology:
The Ing_Fundamental record contains a Title_Category record.
The Title_Category record contains a Title record and a Category record.
All records contain an ID field and one or more data fields (such as text).
I want to select the ID_Title_Category field where Titles.Title = "Hamburger" and Categories.Category = "Meat".
That doesn't make sense. Presumably you mean something like you want select ID_Title_Category from Title_Category wherecondition. But what is condition? What are rows Titles and Categories? You don't need to know more SQL to say that.
You might mean that you want select ID_Title_Category from Title_Category rows where row (ID_Title) is in select ID_Table from Titles where Title = 'Hamburger' and where row (ID_Category) is in select ID_Category from Categories where Category = 'Meat'.
Then it is helpful to know that SQL lets you write (...) in (subselect).
select ID_Title_Category
from Title_Category
where (ID_Title) in (select ID_Title from Titles where Title = 'Hamburger')
and (ID_Category) in (select ID_Category from Categories where Category = 'Meat')
Or you might mean that you want select ID_Title_Category from Title_Category rows TC (say) where there exist values for T.ID_Title & C.ID_Category where row T (say) is in Titles and TC.ID_Title = T.ID_Title and T.Title = 'Hamburger' and row C (say) is in Categories and TC.ID_Category = C.ID_Category and C.Category = 'Meat'.
Then it is good to know that in SQL T cross join U is rows (T.X,...,U.Y,...) where row (T.X,...) is in T and row (U.Y,...) is in U. (, is cross join binding looser than the various joins.)
select TC.ID_Title_Category
from Title_Category TC
cross join Titles T
cross join Categories C
where TC.ID_Title = T.ID_Title and T.Title = 'Hamburger'
and TC.ID_Category = C.ID_Category and C.Category = 'Meat'
Also, T cross join U and condition can be expressed as T join U oncondition.
select TC.ID_Title_Category
from Title_Category TC
join Titles T
on TC.ID_Title = T.ID_Title and T.Title = 'Hamburger'
join Categories C
on TC.ID_Category = C.ID_Category and C.Category = 'Meat'
You could write another version knowing that in SQL there exists a row in subselect when EXISTS(subselect).
We don't need to know constraints (PK, UNIQUE, FK, etc) to query. We do need to what each base table row says about the situation. Then we can express what rows are in the result via what rows are in base tables. To use relation operators we need to know how to translate between predicate expressions & relation expressions. We can also describe the rows in the result via what each result row says about the situation. (Which is how you would justify intuitive use of in.) Is there any rule of thumb to construct SQL query from a human-readable description?

MYSQL: UNION results between two tables where omitting records from first table if PK found in second table

I have two tables products and product_edits which hold product information on the pricelist. My app works in a way that if user changes any product info in products table it inserts it into product_edits table...
PRODUCTS table
pk|code|name |description|price|....
-----------------------------------
1 |QW1X|Product 1|...
2 |LW1X|Product 2|...
3 |DE1X|Product 3|...
PRODUCT_EDITS table
pk|product_id|code|name |description|price|....
-----------------------------------
1 | 2|LW1X|Product 2 new name|...
In above case I would like an SQL that returns records from both tables, but if product is found in product_edits table it selects only from product_edits and not also from products table.
I tried using standrd union but selects all records from both tables:
select code, name, description from products
union
select code, name, description from product_edits
It's better to use EXISTS instead of IN, in this case.
You want the search to stop once you found a match, not go over all of the results from product_edits.
So do it like this:
SELECT
code, name, description
FROM products p
WHERE NOT EXISTS (SELECT 1 FROM product_edits e WHERE e.code = p.code)
UNION
SELECT
code, name, description
FROM product_edits
select code, name, description from products
where code not in(select code from product_edits)
union
select code, name, description from product_edits
You may use IFNULL function
http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_ifnull
If your tables are related, you can try something like this:
SELECT
p.code, IFNULL(pe.name, p.name), IFNULL(pe.description, p.description)
from
products p
left join product_edit pe on (p.id = pe.product_id)
UNION
SELECT
pe2.code, pe2.name, pe2.description
from
product_edits pe2
The first part will give you the products that are only in products table and the products that are in both tables, but with product_edits.description.
The second part will give you the products that are only in products_edits table, because union will remove repeated records

SQL Genius need .. Complex MySQL query

I am trying to optimise my php by doing as much work on the MySQL server as possible. I have this sql query which is pulling data out of a leads table, but at the same time joining two tags tables to combine the result. I am looking to add a company which is linked through a relations table.
So the table that holds the relationship between the two is relations_value which simply states (I add example data)
parenttable (companies) | parentrecordid (10) | childtable (leads) | childrecordid (1)
the companies table has quite a few columns but the only two relevant are;
id (10) | companyname (my company name)
So this query currently grabs everything I need but I want to bring the companyname into the query:
SELECT leads.id,
GROUP_CONCAT(c.tag ORDER BY c.tag) AS tags,
leads.status,
leads.probability
FROM `gs_db_1002`.leads
LEFT JOIN ( SELECT *
FROM tags_module
WHERE tagid IN ( SELECT id
FROM tags
WHERE moduleid = 'leads' ) ) as b
ON leads.id = b.recordid
LEFT JOIN `gs_db_1002`.tags as c
ON b.tagid = c.id
GROUP BY leads.id,
leads.status,
leads.probability
I need to be able to go into the relations_values table and pull parenttable and parentrecordid by selecting childtable = leads and childrecordid = 1 and somehow join these so that I am able to get companyname as a column in the above query...
Is this possible?
I have created a sqlfiddle: sqlfiddle.com/#!2/023fa/2 So I am looking to add companies.companyname as column to the query.
I don't know what your primary keys and foreign keys are that link each table together.. if you could give a better understanding of what ID's are linked to eachother it would make this a lot easier... however i did something that does return the correct result... but since all of the ID's are = 1 then it could be incorrect.
SELECT
leads.id, GROUP_CONCAT(c.tag ORDER BY c.tag) AS tags,
leads.status, leads.probability, companyname
FROM leads
LEFT JOIN (
SELECT * FROM tags_module WHERE tagid IN (
SELECT id FROM tags WHERE moduleid = 'leads' )
) as b ON leads.id = b.recordid
LEFT JOIN tags as c ON b.tagid = c.id
LEFT JOIN relations_values rv on rv.id = b.recordid
LEFT JOIN companies c1 on c1.createdby = rv.parentrecordid
GROUP BY leads.id,leads.status, leads.probability

Improve this query to fetch data from different tables

This is my scenario. I have a table of events with a field type, with values 1 = food, 2 = recipe. Simplifying, my events table have this structure:
id | entity_id | user_id | type | timestamp | field1 | ... field n
Field "entity_id" refers to a unique autoincremental value from "Entities" table. Food and recipe table structure is very similar, with entity_id and user_id fields.
What I want is to get all the common data from the table events of last 10 registers, and fetch some needed fields of corresponding table based on type value of table events. By now I have achieved some quite similar, but not exactly what I want, with this query:
SELECT a.*, b.name, b.field1, b.field2, c.name, c.field1, c.field2
FROM events a
LEFT JOIN foods b ON b.entity_id = a.entity_id
LEFT JOIN recipes c ON c.entity_id = a.entity_id
ORDER BY timestamp DESC LIMIT 10
This allways returns all fields for all tables, with NULL values when the field is not of the type of this specific register.
So I want to get all fields of events table, and name, field1, field2 of the corresponding table.
EDIT:
Here is the sqlfiddle sqlfiddle.com/#!2/18d45/9 I'd like the query returned different field values based on the table. In the example table recipes has description field while foods not. Is it possible?
Please helpe me with this!
You might use a COALESCE to get the first not NULL column:
SELECT a.*,
COALESCE(b.name, c.name),
COALESCE(b.field1, c.field1),
COALESCE(b.field2, c.field2)
FROM events a
...

How do I link tables with id from a list stored as XML in a column

Hopefully the question explains it well. I have a DB for a Library. Since they can be used many times, and contains more data than just a name, I have a table for Authors. Then there's a table for Books. I have no problem linking Authors to Books via a column called Author_id.
What I'm trying to do is have a column called Author_IDs that contains a list of id's, since a book can have multiple IDs. In the Author_IDs column I have:
<id>3478</id>
<id>6456</id>
Using the ExtractValue function in MySQL I can link the table with one or the other id using:
WHERE Author.id = ExtractValue(Book.Author_IDs,"/id[2]") // to get the second ID.
My question is, I want to be able to automatically display all of the authors of a book, but don't know how to link to it more than once, without looping. How can I get the results to show me all of the authors?
(Or is there a better way to accomplish this?)
Firstly, I have to vote against your storage method. Storing data as xml inside a mysql column should be avoided if possible. If you use a normal approach you will find this problem to be much easier.
Create a table:
book_authors
book_id author_id
------- ---------
1 1
1 2
1 3
2 2
2 4
Then to get all of the authors associated with a certain book it's a simple query.
Select
b.book_id,
b.book_name,
GROUP_CONCAT(a.author_name) AS 'authors'
FROM
book_authors ba LEFT JOIN
books b ON ba.book_id = b.book_id LEFT JOIN
authors a ON ba.author_id = a.author_id
GROUP BY
ba.book_id
Not sure I understand completely. Could something like this do the trick?
select a.* from tblBooks b
left join tblAuthors a on (b.authors = concat('%', a.id, '%')
where b = 'book id';
I would have done it like this
Structure
tblBooks
--------
book_id
book_name
tblAuthors
----------
author_id
author_name
tblBooksToAuthors
-----------------
id
book_id
author_id
Query
select a.*
from tblAuthors a
left join tblBooksToAuthors b2a on (b2a.author_id = a.author_id)
where b2a.book_id = {your book id};