I'm trying to create query that will show me table of stock, name of the stock, id, date, url, price and list of prices from the last 2 weeks.
For the 14 days history I used sub-query with group_concat on the select.
But when I use group_concat it's return all results and ignore my limit, so I created another sub-query that will be the 14 prices and the group_concat will make it a list.
The table 'record_log' is records for all stocks:
parent_stock_id - the actual stock this line belongs
price - the price
search_date - date of the price
The second table is 'stocks':
id - id of the stock
name, market_volume....
Here is the problem:
In the sub-sub-query (last line of the SELECT), when i'm filtering parent_stock_id=stocks.id he don't recognize the stocks.id because it belongs to the main query.
How can I take the stock_id from top and pass it to the sub-sub-query? or maybe another idea?
SELECT
stocks.id AS stock_id,
record_log.price AS price,
record_log.search_date,
(SELECT GROUP_CONCAT(price) FROM (SELECT price FROM record_log WHERE parent_stock_id=stocks.id ORDER BY id DESC LIMIT 14) AS nevemind) AS history
FROM stocks
INNER JOIN record_log ON stocks.id = record_log.parent_stock_id
WHERE
record_log.another_check !=0
Thank you!
--- I'm are not really using it for stocks, it's just was the easiest way to explain :)
One method is to use substring_index() and eliminate the extra subquery:
SELECT s.id AS stock_id, rl.price AS price, rl.search_date,
(SELECT SUBSTRING_INDEX(GROUP_CONCAT(price ORDER BY id DESC), ',', 14)
FROM record_log rl2
WHERE rl2.parent_stock_id = s.id
) AS history
FROM stocks s INNER JOIN
record_log rl
ON s.id = rl.parent_stock_id
WHERE rl.another_check <> 0;
Note that MySQL has a settable limit on the length of the group_concat() intermediate result (group_concat_max_len). This parameter is defaulted to 1,024.
Related
So I want to find all items from the parts table for which the price is greater than or equal to the average price of the respective product line.
And I tried it wirh subquerys and Group by but my Subquery returns more than one row. Any Help?
select * from parts
where price >= (select distinct avg(price)
from parts group by productLine)
You have to create a connection between the parts table and the average prices query, because as you have your subquery now, it returns the average price for all productlines, which you most probably you have more than one ... And also the DISTINCT doesn't help here, unless all of your productlines have the extact same AVG(price) -- which is quite unlikely.
With newer versions of mysql you can use a common table expression
with prices(avgprice, productline) as (
select avg(price), productline
from parts
group by productline)
select pa.*
from parts pa inner join prices pr on pa.productline = pr.productline
where pa.price >= pr.avgprice
If you are on a older version of mysql, which doesn't support CTE, you can also join on the result of a subquery
select pa.*
from parts pa inner join (
select avg(price) as avgprice, productline
from parts
group by productline) pr on pa.productline = pr.productline
where pa.price >= pr.avgprice
or you can just limit your subquery on the respective productline
select *
from parts p
where price >= (
select avg(price)
from parts pa
where pa.productline = p.productline)
There are three tables
Inventory - Which contains the stock information
Order - Which contains the store information of an order
OrderParts - Which contains the Parts associated with the order
Inventory Table
Order Table
Order Parts Table
Below Expected Report needs to be generated
Query Tried to achieve the above result
SELECT
inventory.partNumber, inventory.storeId, SUM(parts.quantity) as orderedQuantity,
inventory.availableQuantity
FROM
(SELECT *, SUM(availableQuantity) AS availQty
FROM
inventory AS inventory
GROUP BY storeId , partNumber) AS inventory
LEFT JOIN
(SELECT
*
FROM
order
GROUP BY storeId) AS order ON order.storeId = inventory.storeId
LEFT JOIN
(SELECT
*
FROM
orderParts) AS parts ON inventory.partNumber = parts.partNumbe
where inventory.partNumber in ("A1234", "B1234");
GROUP BY order.storeId , parts.partNumber
Getting null for Ordered Quantity
Kindly let me know the way to get the cumulative Ordered quantity as expected. Thanks in Advance.
A relatively simple method is union all and aggregation:
select storeid, partnumber,
sum(availableqty) as availableqty,
sum(orderedqty) as orderedqty
from (select storeid, partnumber, availableqty, 0 as orderedqty
from inventory
union all
select o.storeid, op.partnumber, 0, op.quantity
from orderparts op join
orders o
on op.ordernumber = o.ordernumber
) sp
group by storeid, partnumber;
Your question doesn't explicitly describe the filters, but you can add filters in either the subqueries or the outer query.
I have a table with products from shops. These products have a valid_from and valid_to date. In my query, I want to have only the first x records of each shop which are currently valid, ordered by last insert desc.
I am currently using the following query:
SELECT * FROM
(
SELECT
s.id as shopid, ss.name as shopname, p.name as productname, p.validfrom, p.validto
FROM
product p
JOIN
shop s ON p.shopid = s.id
WHERE
s.status = 'Active' AND
(now() BETWEEN p.validfrom and p.validto)
ORDER BY p.insert DESC
) as a
GROUP BY
shopid
ORDER BY
shopname asc
This obviously only gives me the latest record of each shop, but I want to have latest 2 or 3 records. How can I achieve this?
Bonus question: I want to differ per shop. So for shop A I'd like to have only the first record and for shop B the first two records. You may assume I have some database field for each shop that holds this number, like s.num_of_records.
The similar issue (possible duplicate) got me in the right direction, but it not completely solve my problem (see latest comment)
It works by giving each record a rank based on the previous shopid. If the shopid is the same, I rank it +1. Otherwise I rank it 1.
There still is a problem however. Even though I'm using order by shopid, it is not ranking correctly for all the shops. I added the lastshopid in the query to check and although the records are ordered by shop in the result, the lastshopid sometimes has another id. I think it must be because the ordering is done at the end instead of the beginning.
Anyone has an idea how to solve this? I need the shops in the right order to get this rank solution working.
You can use an additional LEFT JOIN with the product table to count the number of products from the same shop that have been inserted later. That number can be compared with your num_of_records column.
SELECT s.id as shopid, s.name as shopname,
p.name as productname, p.validfrom, p.validto
FROM shop s
JOIN product p
ON p.shopid = s.id
LEFT JOIN product p1
ON p1.shop_id = p.shop_id
AND p1.validfrom <= NOW()
AND p1.validto >= NOW()
AND p1.`insert` > p.`insert`
WHERE s.status = 'Active'
AND p.validfrom <= NOW()
AND p.validto >= NOW()
GROUP BY p.id
HAVING COUNT(p1.id) + 1 <= s.num_of_records
ORDER BY shopname asc
Indexes that might help: shop(status, name), product(shop_id, validfrom) or product(shop_id, validto) (probably the second one).
Note 1: If you have inserted two products at the same time (same second) for the same shop and both of them are candidates to be the last in the limited list for that shop, they will be selected both. That will not happen, if you use the AUTO_INCREMENT column insted of the insert column.
Note 2: Depending on the group size (number of products per shop) this query can be slow.
I have a two tables, one called entities with these relevant columns:
id, company_id ,and integration_id. The other table is transactions with columns id, entity_id and created_at. The foreign keys linking the two tables are integration_id and entity_id.
The transactions table shows the number of transactions received from each company from the entities table.
Ultimately, I want to find date range with highest volume of transactions occurring and then from that range find the average number of days between transaction for each company.
To find the date range I used this query.
SELECT DATE_FORMAT(t.created_at, '%Y/%m/%d'), COUNT(t.id)
FROM entities e
JOIN transactions t
ON ei.id = t.entity_id
GROUP BY t.created_at;
I get this:
Date_FORMAT(t.created_at, '%Y/%m/%d') | COUNT(t.id)
+-------------------------------------+------------
2015/11/09 4
etc
From that I determine the range I want to use as 2015/11/09 to 2015/12/27
and I made this query
SELECT company_id, COUNT(t.id)
FROM entities e
INNER JOIN transactions t
ON e.integration_id = t.entity_id
WHERE tp.created_at BETWEEN '2015/11/09' AND '2015/12/27'
GROUP BY company_id;
I get this:
company_id | COUNT(t.id)
+-----------+------------
1234 17
and so on
Which gives me the total transactions made by each company over this date range. What's the best way now to query for the average number of days between transactions by company? How can I sub-query or is there a way to use the AVG function on dates in a WHERE clause?
EDIT:
playing around with the query, I'm wondering if there is a way I can
SELECT company_id, (49 / COUNT(t.id))...
49, because that is the number of days in that date range, in order to get the average number of days between transactions?
I think this might be it, does that make sense?
I think this may work:
Select z.company_id,
datediff(max(y.created_at),min(created_at))/count(y.id) as avg_days_between_orders,
max(y.created_at) as latest_order,
min(created_at) as earliest_order,
count(y.id) as orders
From
(SELECT entity_id, max(t.created_at) latest, min(t.created_at) earliest
FROM entities e, transactions t
Where e.id = t.entity_id
group by entity_id
order by COUNT(t.id) desc
limit 1) x,
transactions y,
entities z
where z.id = x.entity_id
and z.integration_id = y.entity_id
and y.created_at between x.earliest and x.latest
group by company_id;
It's tough without the data. There's a possibility that I have reference to integration_id incorrect in the subquery/join on the outer query.
Is there a way of limiting the result of a subquery? The sort of thing I'm trying to achieve can be explained by the query below:
SELECT *
FROM product p
JOIN (
SELECT price
FROM supplierPrices sp
ORDER BY price ASC
LIMIT 1
) ON (p.product_id = sp.product_id)
The idea would be to get only the lowest price for a particular product from a table that had all the price data in it. LIMIT 1 is limiting the entire result set, whereas excluding it would result in a row being returned for each price, with duplicated product data. I tried GROUP BY price as well to no avail.
Once the limit is working I need to apply IFNULL as well, so that if there is no price found at all for any supplier it can return a supplied string, such as "n/a" rather than NULL. I assume that would just mean modifying the SELECT as below, and changing the JOIN to a LEFT JOIN?
SELECT *, IFNULL(price,'n/a')
Just to expand on Wolfy's answer slightly, and bearing in mind this is untested:
SELECT *
FROM product p
LEFT JOIN (
SELECT product_id, MIN(price)
FROM supplierPrices sp
GROUP BY product_id
) x ON (p.product_id = x.product_id)
And, as you say, it should just be a matter of doing an IFNULL on that column to replace it with something sensible.