I have a question about DQL query.
I have these tables: 'orders', 'orders_kitchen', 'orders_institution' and 'variants'.
From the table 'variants', I get order IDs that have already been made offers.
$orders = $em->createQuery("SELECT o
FROM AppBundle:Orders o
JOIN AppBundle:OrdersInstitution oi
WHERE oi.idInstittuion = :institution AND o.idorder = oi.idOrder AND o.finalDeal IS NULL
ORDER BY o.idorder DESC")
->setParameter("institution",$institution)->getResult();
When a customer leaves the order, he may proceed in three ways:
Do not add a record to the table 'orders_institution' some institutions going and add an entry in the table of certain types of cuisines id
Does not add an entry in any of the tables
Add an entry in the table 'orders_kitchen', some types of cuisines ID works with this institution
I need to find all orders that have not selected any one institution, and none of the types of cuisines, or at least one of the kitchen works with the institution (this can be an array).
And I don't want to choose orders whose ID is in the table 'variants'.
You can try it with SQL something like (DQL doesnt performe well with lot of joins) :
$sql = 'SELECT * FROM Orders o JOIN
(SELECT o1.id FROM Orders o1 WHERE o1.cuisine IS NULL OR o1.institution IS NULL) o1 JOIN
(SELECT * FROM Orders o2 INNER JOIN Cuisine c ON c.insitution_id = '.$institution_id.') o2 JOIN (your query);';
Something like this should do it, not expert in SQL i usually end up trying until i get it !
I dont think its correct tho but at least its a start :p
Related
I have more than one shop in ps_shop table and its some of shop have in ps_storeinfo table but those shop of ps_shop table are not in ps_storeinfo table that are needed to insert into ps_storeinfo with user id and shop name. Here shopname of ps_shop table = storename in ps_storeinfo table. Here I have written sql query for this and I am getting all data but problem is more than one user is coming by my SQL if it have more than one user. I need one user for one shop.
In ps_ employee_shop table user is assigned for shop base on shop id. And In ps_ employee table is for user. This is for prestashop 1.6.
My SQL is given below :
$table_prefix = _DB_PREFIX_;
'SELECT ps.*, pe.email, pe.firstname, pe.lastname, pes.id_employee,psi.storename
FROM '.$table_prefix.'shop ps
LEFT JOIN '.$table_prefix.'storeinfo psi ON ps.name = psi.storename
INNER JOIN '.$table_prefix.'employee_shop pes ON ps.id_shop = pes.id_shop
INNER JOIN '.$table_prefix.'employee pe ON pes.id_employee = pe.id_employee where ps.id_shop <>1 and pe.id_employee <>1
GROUP BY pes.id_employee
';
Output image is:
Well, if more than one entity exists in the table on the right side of the JOIN with the matching ON key any relational DB engine will return one row for each matching entity on the right side, duplicating the left side of the JOIN clause.
In the scenario described you need to decide which user you want to return. The first one sorted alphabetically? The one created most recently?
Based on the answer you will need to use a JOIN with a correlated subquery. Here's an example for getting the employee with the highest value of id_employee:
SELECT
ps.*, pe.email, pe.firstname, pe.lastname, pes.id_employee,psi.storename
FROM
'.$table_prefix.'shop ps
LEFT JOIN '.$table_prefix.'storeinfo psi ON ps.name = psi.storename
INNER JOIN (
SELECT
pe.email, pe.firstname, pe.lastname, pes.id_employee
FROM
'.$table_prefix.'employee pe
'.$table_prefix.'employee_shop pes ON pes.id_employee = pe.id_employee
WHERE
pe.id_employee <> 1
AND ps.id_shop = pes.id_shop
ORDER BY
pe.id_employee DESC
LIMIT 1
)
WHERE
ps.id_shop <>1
As you can see what this is really doing is limiting the resulting list of employees to just one record to avoid duplication. In this case the list is ordered by id_employee, but the correct ordering depends on the business logic that needs to be implemented.
I want to get a list of category items and display the total amount linked to those categories. I have the "amount" field in the "transaction" table and I want to link it to category table.
This is how my tables are:
Category Master
Subcategory Master
Item Master
Transaction
So to get my "Amount" field to category, I would have to pass a certain common column between them. I have CategoryID in SubCategory master, subcatid in item master and similarly itemid in transaction.
Earlier when I grouped the amount using transaction date, the process went smoothly:
SELECT TransactionDate, SUM(Amount) FROM transaction GROUP BY MONTH(TransactionDate)
Now the problem I'm facing with grouping it using categoryname is that all of the amount seems to be =50 whereas it is still different in the database. I know that this is something really silly, but I am comparatively new to programming and not sure how to use logic appropriately.
SELECT categorymaster.CategoryName, transaction.Amount
FROM categorymaster
INNER JOIN subcategorymaster
INNER JOIN itemmaster
INNER JOIN transaction
GROUP BY categorymaster.CategoryName
This answer assumes your primary key in each table is named "ID". You didn't provide that info.
SELECT categorymaster.CategoryName, sum(transaction.Amount)
FROM categorymaster
INNER JOIN subcategorymaster
ON subcagetorymaster.CategoryId = categorymaster.ID
INNER JOIN itemmaster
ON itemmaster.SubCatId = subcategorymaster.ID
INNER JOIN transaction
ON transaction.ItemId = itemmaster.ID
GROUP BY categorymaster.CategoryName
I have searched around for an issue like I have but I have not found anything :-( , so, I have decided to open a question. I'm working on a travel agency website and I'm stuck. I have 6 tables:
1. category
2. country
3. city
4. type
5. offer
6. price
Now, the relations of each one is like this: in offer table are recorded id's of category, country, city, type and, in price table is recorded offer id. In this way, via admin panel, the process starts by creating a new offer and after that, creating prices for that offer. This is way the offer id is recorded in price table and not inverse.
What I have right now is the following:
SELECT DISTINCT
price.prFood,
offer.*
FROM
category,
country,
city,
`type`,
price
INNER JOIN offer
ON price.prOfferID = offer.offerID
WHERE offerType = typeID
AND categoryID = offerCategory
AND countryID = offerCountry
AND prOfferID = offerID
AND offerActive = '1'
AND offerCity = cityID ;
This query shows correctly, only once, every offer that has a price but, what I need is to show also offers that are active and don't have a price. So, I need a little help on the correct query to show all offers that are active, have or don't have a price.
Use left join for your price table and move where condition in on clause. I have used aliases to give short names to table, so if I have not selected proper columns, please use right aliases for the columns.
SELECT DISTINCT
p.prFood,
o.*
FROM
offer o
LEFT JOIN price p ON o.offerID = p.prOfferID
INNER JOIN category ca ON o.offerCategory = ca.categoryID
INNER JOIN country c ON o.offerCountry = c.countryID
INNER JOIN city ci ON o.offerCity = ci.cityID
INNER JOIN `type` t ON o.offerType = t.typeID
AND o.offerActive = '1'
I have four tables:
users, orders, orders_product and products.
They are connected to each other by foreign key
user tables contains: id, name, email and username.
product table contains: id, product_name, product_description and product_price
orders table contains: id, u_id(foreign key).
orders_product table contains: id, product_id(foreign key), order_id(foreign key).
Now I was trying to fetch the name of a user with the total price of a particular order that he has placed.
The maximum I could went for was something like this:
SELECT prod.order_id,
SUM(product_price) AS Total
FROM products
INNER JOIN
(SELECT orders.id AS order_id,
orders_product.product_id
FROM orders
INNER JOIN orders_product ON orders.id = orders_product.order_id
WHERE order_id=1) AS prod ON products.id = prod.product_id;
It showed me total price of a particular order. Now I have two questions:
Is that query correct. It looks like a very long query. Can the same result be achieved with a smaller one?
How to fetch the name of a user with the total price of a particular order that he has placed.
Hi some addition to #Gordon Linoff
your query seems ok.
if you store your price data in order_products it will be good and some benefit, one of these benefit is aggregation will be simple. Second benefit if product price change it will not affect to order.
Your query is correct for one order, but it can be improved:
Don't use a subquery unless necessary. In MySQL this introduces additional overhead.
You are only looking at one order, which seems on the light site. You should remove the where clause.
You should be using a group by because you want aggregation.
You need to join in the user table to get the name.
I also added table aliases (abbreviations for table names). This makes the query a bit more readable:
SELECT u.name, SUM(p.product_price) as Total
FROM orders_product op INNER JOIN
orders o
ON o.id = op.order_id INNER JOIN
products p
ON p.id = op.product_id INNER JOIN
users u
on o.userid = u.id
WHERE op.order_id = 1
GROUP BY u.name;
Your SQL is wrong. Because You want to calculate specific to user. But your SQL is specific to Order. Your SQL will give result for One Order. Please make it User Specific by giving user name or what ever is unique.
I have a database with three tables:
Products
MaterialsProducts
Materials
The relationship between the tables are like this:
Materials 1-* MaterialsProducts *-1 Products
Quite often I need to retrieve 200+ products and their related material data (from the Materials table).
Currently it is done like this:
SQL: select all relevant products
PHP: iterate through the selected products, calling the database to select material data for each product(generating a database call for each product!)
Is there a way to select all relevant products + their material data at the same time? And still have each product only take up one row in the result.
So the solution shouldn't be "SELECT * FROM products p, materialsproducts mp, materials m WHERE p.id = mp.productid AND m.id = mp.materialid WHERE x". (That SELECT would make each product take up more than one row in the result.)
you can use left join to get all data you need
documentation here
Your query have a mistake
"SELECT * FROM `products` p LEFT JOIN `materialsproducts` mp on p.`id` = mp.`productid` LEFT JOIN `materials` m ON m.`id` = mp.`materialid` WHERE $whateveryouneed"
remember to not limit your WHERE to only 1 ID otherwise you will need more queries.
UPDATED
as asked
products has a 1-* relationship with both materialsproducts and typesproducts. materialsproducts has a *-1 relationship with materials. typesproducts has a *-1 relationship with types.
So you can make a left join query as above in this way
SELECT * FROM `products` p
LEFT JOIN `materialsproducts` mp
ON p.`id` = mp.`productid`
LEFT JOIN `materials` m
ON mp.`mp_field_id_here` = m.`m_field_id_here` //here you need to change with actual field to compare
LEFT JOIN `typesproducts` tp
ON p.`id` = tp.`tp_field_id_here` //here you need to change with actual field to compare
LEFT JOIN `types` t
ON tp.`tp_field_id_here` = t.`t_field_id_here` //here you need to change with actual field to compare
then you can add a where statment to limit result to something that suits you
WHERE WHATEVER_YOU_NEED
UPDATED AGAIN
to limit result to only some filed just change * to something specific as
"SELECT p.`Product_Name`, m.`Material_1`, m.`Material_2, m.`Material_3`, t.`Type_1`, t.`Type_2` FROM .....
NOTE I assume you retrieve material 1, material 2, material 3 from material table wich is why i used as prefix m. Either way i used as prefix t for type 1 and type 2 because i thought they are fileds of type table, otherwise you can change them according to your needs.
Try
SELECT p.*, mp.*,m.*
FROM products p
JOIN materials m ON p.id=m.prd_id
JOIN materialsproducts mp ON m.mp_id=mp.id;
It is not simple to have a query like this compress the materials data into a single row for each product - so I don't think that plan will work well for you.
What I would recommend instead is to use a normal JOIN query (much like the one you put in your question and rejected), then use PHP code to deal with the cases where a single product has multiple rows in the result set because it is linked to multiple materials.
You could use GROUP_CONCAT to combine materials related to the same product into a single list while grouping by products:
SELECT
p.ProductID,
p.ProductName,
GROUP_CONCAT(m.MaterialName) AS Materials
FROM Products p
INNER JOIN MaterialsProducts mp ON p.ProductID = mp.ProductID
INNER JOIN Materials m ON m.MaterialID = mp.MaterialID
GROUP BY
p.ProductID,
p.ProductName
;