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
...
Related
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?
I have my shop database and I want to join two tables together.
id_order | reference | id_shop_group | id_shop | id_carrier | id_lang | id_customer | id_cart
This the header row of my orders table and below is the header of customers table.
id_customer | id_shop_group | id_shop | id_gender | firstname | lastname
What I want to do is to join them based on id_customer column. More specifically I want to add all columns of customers except the ones that are already there to orders table based onid_customer. After joining the tables should look like this:
id_order|reference|id_shop_group|id_shop|id_carrier|id_lang|id_customer|id_cart|id_gender|firstname|lastname
When searching for a solution I found INNER JOIN keyword, but I'm not sure how to use it the way I want.
We don't "Add columns to a table". We, instead, submit SQL to the database that returns the result set that we want. In your case we want to Join the two tables and we can do that using an INNER JOIN on your id_customer field that is common between the two tables. We can turn that into it's own table if you want to hold, permanently, those results. It would look something like
SELECT
orders.id_order,
orders.reference,
orders.id_shop_group,
orders.id_shop,
orders.id_carrier,
orders.id_lang,
orders.id_customer,
orders.id_cart,
customer.id_gender,
customer.firstname,
customer.lastname
FROM orders INNER JOIN customer on orders.id_customer = customer.id_customer;
You can tweak the list of fields to be returned from the joining of these tables to suit your needs.
The fact that id_shop and id_shop_group are in both tables suggests they are part of a composite key. You may need to join using all three shared columns to guarantee unique rows. Otherwise you may retrieve duplicate order rows where the customer belongs to more than one shop.
e.g.
SELECT
...
FROM orders INNER JOIN customer on orders.id_customer = customer.id_customer
and orders.id_shop_group = customer.id_shop_group
and orders.id_shop = customer.id_shop
I'm trying to add a column to a Mysql result using a subquery,
Suppose i have a table 'Cars' and a table 'Cars usage'
Table Cars has a column "serial_number" and the Cars usage table has a column "serial_number" as well:
So i wanna generate a result with the car name as first column and car usage as second:
Table cars:
-model
-serial_number
Table carsusage
-date
-serial_number
What i would like to achieve would look like so:
Model | Usage count
--------------------
|bar | 1500 |
|foo | 700 |
Ideally i need a sub-query, that, while querying the cars table, spits a query to the Cars usage table counting:
SELECT model, serial_number AS sn,(SELECT COUNT(serial_number) FROM cars_usage WHERE serial_number=sn) FROM cars;
So basically i would like to use the serial_number AS sn as a local variable and add the result of the count operation as second column.
Any advice?
No that much experience with querying a db here.
Thx
If you want usage per serial number:
select model, serial_number, count(*) from cars inner join carsusage on cars.serial_number=carsusage.serial_number where cars.serial_number=$var group by 1,2
or if you want usage per model:
select model, count(*) from cars inner join carsusage on cars.serial_number=carsusage.serial_number where cars.serial_number=$var group by 1
Why not just try something like
SELECT model,
serial_number AS sn,
(SELECT COUNT(serial_number) FROM cars_usage cu WHERE cu.serial_number=c.serial_number)
FROM cars c;
Where you provide aliases for the tables, and then prefix the fields with the aliases.
You could also try a LEFT JOIN (do be carefull of inner join, because if there a no usages, it will not return a 0 entry for that car).
select c.model,
c.serialnumber sn,
count(cu.*)
from cars c LEFT join
carsusage cu on c.serial_number=cu.serial_number
GROUP BY c.model,
c.serialnumber
In my MySQL database I have a table of products along the lines of
id | type | name | weight | base_price | [...]
where id is a primary key and type is an ENUM('personal','industrial'). Personal and industrial products both have some additional information stored in products_personal and products_industrial tables. Both are of the form
pid | additional info [...]
where pid is foreign keyed with products.id and additional info is different for products_personal and products_industrial. In my table I have two functions (through CREATE FUNCTION), PRICE_PERSONAL(...) and PRICE_INDUSTRIAL(...). These functions use the base_price and some of the additional info to compute a final price.
I wish to create a view of id | type | name | [...] | price for all of my products. My current candidate is
CREATE VIEW foo AS
SELECT id, type, name, [...], PRICE_PERSONAL(params) AS price
FROM products
INNER JOIN products_personal ON products.id = products_personal.pid
UNION
SELECT id, type, name, [...], PRICE_INDUSTRIAL(params) AS price
FROM products
INNER JOIN products_industrial ON products.id = products_industrial.pid
But this is a but bulky and seems to result in poor ORDER BY performance (as it needs to sort the un-indexed UNION results).
Is there a cleaner table or query structure to accomplish this type of query?
Didn't actually test it, but try something like this:
CREATE VIEW foo AS
SELECT id, type, name, [...], PRICE_PERSONAL(params) AS price
FROM products
INNER JOIN products_personal ON products.id = products_personal.pid
WHERE type = 'personal'
UNION ALL
SELECT id, type, name, [...], PRICE_INDUSTRIAL(params) AS price
FROM products
INNER JOIN products_industrial ON products.id = products_industrial.pid
WHERE type = 'industrial'
The idea is to cut-off "wrong" rows early by filtering on products.type. Also, I should give credit to #ypercube for spotting UNION ALL.
What are the fields under ORDER BY? They should probably be indexed.
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.