MySQL join to pivot question - mysql

I'm sure this is simple but my brain just isnt working today!
I have a table products, lets just assume it contains p_id, i have another table - a pivot table - which references between products and another table attributes, this table is products_to_attributes and contains pta_aid (attribute id) and pta_pid (product id)
Hopefully this (incorrect) query will show what i want to do better than i can explain it:
SELECT `p_id` FROM `products`
LEFT JOIN `products_to_attributes` ON (`pta_pid` = `p_id`)
WHERE ((`pta_aid` = '1' OR `pta_aid` = '2') AND(`pta_aid` = '3'))
I want to be able to group together attributes where a product must have attribute 1 Or attribute 2 AND have attribute 3.

If I understand your need correctly, you pretty much have to have two EXISTS clauses:
SELECT p_id FROM products PR
WHERE EXISTS (SELECT p_id FROM products_to_attributes WHERE (pta_aid = 1 OR pta_aid=2) AND pta_pid=PR.p_id )
AND EXISTS (SELECT p_id FROM products_to_attributes WHERE pta_aid = 3 AND pta_pid=PR.p_id)

SELECT p.`p_id` FROM `products` p
LEFT JOIN `products_to_attributes` pta ON (p.`p_id` = pta.`pta_pid`)
Name the tables and specify which field is from which table. However how a field can be both 1 and 3 in a row? there is a logical problem in your where clause.

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?

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

MySQL Queries - Selecting from 2 tables and if exists in the other check field

I am trying to pull products from a table called products, I also have a table called product_ranges.
products
--------
id
name
model
product_ranges
--------------
id
product_id
other_id
SELECT p.id
FROM products As p
LEFT JOIN product_ranges As pr ON (pr.product_id = p.id AND pr.other_id = 16)
This will select all products and include the product_ranges table columns too if the product exists in it but if it does exist in this table and the other_id does not equal 16 I don't want the product to be in the returned results but if the product doesn't exist at all in the other table I want it in the results still.
I am sure I have done this years ago but can't think of the SQL for it - if anyone knows the right query I would be grateful, thanks.
Updated:
SELECT p.id
FROM products
LEFT JOIN product_ranges pr ON pr.product_id = p.id
WHERE (pr.product_id IS NULL OR pr.other_id = 16)

A Better way to optimize these MySQL queries

I have two MySQL tables:
attributes (attributeid, name)
productsattributes (productid, attributeid, displayvalue)
The required is for each attribute name called "Product Type" get all other attributes associated with this "Product Type". As an example — attributes table will look like:
attributeid name
1 A
2 B
3 Product Type
4 D
productsattributes table will look like:
productid attributeid displayvalue
1 3 FAN
1 1 Brown
1 2 Stand
2 3 FAN
2 4 D
3 3 CAR
3 4 imported
So the final result should be:
FAN (A,B, Product Type,D)
CAR (Product Type, imported)
Here is my try:
first I get all the "displayvalues" from productattributes:
SELECT DISTINCT displayvalue
FROM productsttributes
WHERE attributeid = 3;
then I loop through each "displayvalues" to find the other attributes:
SELECT a.name
FROM attributes a
INNER JOIN productsattributes pa
ON pa.attributeid = a.attributeid AND productid in (
SELECT productid
FROM productsttributes
WHERE dispalyvale = '$displayvalue')
ORDER BY a.name;
The problem is the productattributes table has about 7 million rows, so my script is taking forever .. of course I am not looking for 10 minutes solution but at least it will improve my queries a bit.
I would start with the following statements:
ALTER TABLE attributes ADD CONSTRAINT p_attributes PRIMARY KEY (attributeid);
ALTER TABLE productsattributes ADD CONSTRAINT p_productsattributes
PRIMARY KEY(productid, attributeid);
ANALYZE TABLE attributes, productsattributes;
This will make sure all important fields are indexed.
The query might look like this (also on SQL Fiddle):
SELECT trg.displayvalue,
group_concat(a.name ORDER BY trg.productid, a.attributeid)
FROM (
SELECT t.productid,t.displayvalue
FROM attributes a
JOIN productsattributes t USING (attributeid)
WHERE a.name = 'Product Type') AS trg
JOIN productsattributes p ON p.productid = trg.productid
JOIN attributes a ON a.attributeid = p.attributeid
GROUP BY trg.displayvalue
ORDER BY 1;
Please, kindly include the EXPLAIN output of your's and this queries into your question.
Try this ::
Select displayvalue, attribute_name
from
(Select
product_id from productsattributes pa inner join attributes_table at on (pa.attributeid=at.id) where at.name=?) as productList
inner join productsattributes pa2 on(pa2.product_id=productList.product_id)
inner join attributes_table at2 on (pa2.attributeid=at2.id)

Change database structure: need an SQL query

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.