I have an index table of entity attribute values that looks like this:
+-----------+--------------+----------+-------+
| entity_id | attribute_id | store_id | value |
+-----------+--------------+----------+-------+
| 38 | 190 | 1 | 22 |
| 38 | 190 | 1 | 23 |
| 39 | 190 | 1 | 22 |
| 39 | 190 | 1 | 23 |
| 39 | 190 | 1 | 42 |
| 40 | 190 | 1 | 22 |
| 41 | 190 | 1 | 54 |
| 42 | 190 | 1 | 54 |
| 43 | 190 | 1 | 22 |
| 44 | 190 | 1 | 22 |
| 45 | 190 | 1 | 54 |
+-----------+--------------+----------+-------+
As you can see, a single entity can have multiple values for a single attribute (entity_id 38 has values 22,23) and these values are not unique per entity (entity_id 38,39 both share value 22).
The first problem to solve is getting the number of distinct entities per value; this is easily accomplished with:
SELECT value, COUNT(entity_id) AS count
FROM catalog_product_index_eav
WHERE attribute_id=190
GROUP BY value;
which results in:
+-------+-------+
| value | count |
+-------+-------+
| 22 | 5 |
| 23 | 2 |
| 42 | 1 |
| 54 | 3 |
+-------+-------+
My question is how can I nest an OR condition in this count, namely: for some specific value Y, for each value X, count the number of entities that have either value X or Y.
I would like to do this in a single query. For instance, for attribute_id 190 and value 23, the output from above example should be:
+-------+-------+
| value | count |
+-------+-------+
| 22 | 5 | # all entities with value 22 happen to have 23 as well
| 23 | 2 | that is, one is a subset of the other
| 42 | 2 | # intersection is nonempty
| 54 | 5 | # sets are disjoint
+-------+-------+
select c1.value,
( SELECT COUNT(DISTINCT entity_id) as count
FROM catalog_product_index_eav
where attribute_id=81
and (value=c1.value || value=7) ) as count
FROM catalog_product_index_eav c1
WHERE attribute_id=81
GROUP BY c1.value
Try to use
Select C.value, max(C.count) from (
SELECT A.value, (Select COUNT(B.entity_id) from FROM catalog_product_index_eav B
WHERE B.attribute_id=A.attribute_id and (B.value=A.value or B.value=23)) AS count
FROM catalog_product_index_eav A
WHERE A.attribute_id=190) C group by C.value
It gives you both results in single query if it is satisfied your output.
SELECT i.value AS [value], COUNT(i.entity_id) AS [count],
(SELECT COUNT(b.entity_id) tot FROM catalog_product_index_eav b
WHERE b.entity_id IN (SELECT v.entity_id FROM
catalog_product_index_eav v WHERE v.VALUE = i.value)) AS [total_count]
FROM catalog_product_index_eav i
WHERE i.attribute_id=190
GROUP BY i.value
Related
I have a table called related_clues which lists the id's of pairs of clues which are related
| id | clue_id | related_clue_id | relatedness |
+----+---------+-----------------+-------------+
| 1 | 1 | 232 | 1 |
| 2 | 1 | 306 | 1 |
| 3 | 1 | 458 | 1 |
| 4 | 2 | 620 | 1 |
| 5 | 2 | 72 | 1 |
| 6 | 3 | 212 | 1 |
| 7 | 3 | 232 | 1 |
| 8 | 3 | 412 | 1 |
| 9 | 3 | 300 | 1 |
+----+---------+-----------------+-------------+
Eventually after a while we may reach two id's such as:
+--------+---------+-----------------+-------------+
| id | clue_id | related_clue_id | relatedness |
+--------+---------+-----------------+-------------+
| 121267 | 1636 | 38 | 1 |
| 121331 | 1636 | 38 | 1 |
+--------+---------+-----------------+-------------+
So in this case, for two distinct id values, we have the same (clue_id, related_clue_id) pair
In this case I would like the relatedness value to be updated to 2, signalling that there are two examples of this (clue_id, related_clue_id) pair. Like so:
+--------+---------+-----------------+-------------+
| id | clue_id | related_clue_id | relatedness |
+--------+---------+-----------------+-------------+
| 121267 | 1636 | 38 | 2 |
| 121331 | 1636 | 38 | 2 |
+--------+---------+-----------------+-------------+
So essentially I would like to run some SQL that sets the relatedness value to the number of times a (clue_id, related_clue_id) pair appears.
When I have no relatedness column present, and I simply run the SQL:
SELECT id, clue_id, related_clue_id, COUNT(*) AS relatedness
FROM `related_clues`
GROUP BY clue_id, related_clue_id
It gives me the required result, but of course this doesn't store the relatedness column, it simply shows the column if I run this select. So how do I permanently have this relatedness column?
You could use a update with join
Update related_clues a
INNER JOIN (
SELECT clue_id, related_clue_id, COUNT(*) AS relatedness
FROM `related_clues`
group by clue_id, related_clue_id
having count(*) = 2
) t on t.clue_id = a.clue_id
and t.related_clue_id = a.related_clue_id
set a.relatedness = t.relatedness
I would approach this as an update/join but filter out rows that don't need to be updated:
update related_clues rc join
(select clue_id, related_clue_id, COUNT(*) AS cnt
from `related_clues`
group by clue_id, related_clue_id
) t
on t.clue_id = rc.clue_id and
t.related_clue_id = rc.related_clue_id
set rc.relatedness = t.relatedness
where rc.relatedness <> t.relatedness;
I am trying to extract data from tables with the results from a previous search. I am not really familiar with database query's and have made one that will crash my computer from drawing too much memory.
This data is coming from a board tester and I want certain information.
How many boards were ran during a given period
How many failed
All the failure data for those boards EDIT: This is the one I need to figure out. See Edit at bottom.
The first time a board is ran it creates a record in the Board table
+----------+-------+-----+
| Board_id | Board | rev |
+----------+-------+-----+
| 1 | 1234 | 1 |
| 2 | 1234 | 1 |
| 3 | 1235 | 2 |
| 4 | 5869 | 15 |
+----------+-------+-----+
Each time the board is ran it creates a Test record
+----------+----------+---------+---------------------+
| Test_id | Board_id | Operator| Date_Time |
+----------+----------+---------+---------------------+
| 34 | 1 | 1 | 2017-08-02 09:13:34 |
| 35 | 1 | 1 | 2017-08-02 09:13:36 |
| 36 | 1 | 1 | 2017-08-02 09:13:39 |
| 37 | 2 | 1 | 2017-08-02 09:14:10 |
| 38 | 3 | 1 | 2017-08-02 09:16:24 |
| 39 | 3 | 2 | 2017-08-03 10:40:45 |
| 40 | 4 | 2 | 2017-08-03 10:43:34 |
+----------+----------+---------+---------------------+
...and Results are stored in Results
+-----------+---------+--------+-------------+-------------+
| Result_id | Test_id | Result | Upper_Limit | Lower_Limit |
+-----------+---------+----------------------+-------------+
| 40 | 34 | 2 | 4 | 1 |
| 41 | 34 | 3 | 4 | 1 |
| 42 | 34 | 4 | 4 | 1 |
| 43 | 34 | 0 | 4 | 1 |
| 44 | 35 | 2 | 4 | 1 |
| 45 | 35 | 3 | 4 | 1 |
| 46 | 35 | 4 | 4 | 1 |
| 47 | 35 | 0 | 4 | 1 |
| 48 | 36 | 2 | 4 | 1 |
| 49 | 36 | 3 | 4 | 1 |
| 50 | 36 | 4 | 4 | 1 |
| 51 | 36 | 2 | 4 | 1 |
| 52 | 37 | 2 | 4 | 1 |
| 53 | 37 | 3 | 4 | 1 |
| 54 | 37 | 4 | 4 | 1 |
| 55 | 37 | 2 | 4 | 1 |
| 56 | 38 | 2 | 4 | 1 |
| 57 | 38 | 3 | 4 | 1 |
| 58 | 38 | 4 | 4 | 1 |
| 59 | 38 | 5 | 4 | 1 |
| 60 | 39 | 2 | 4 | 1 |
| 61 | 39 | 3 | 4 | 1 |
| 62 | 39 | 4 | 4 | 1 |
| 63 | 39 | 5 | 4 | 1 |
| 64 | 40 | 2 | 4 | 1 |
| 65 | 40 | 3 | 4 | 1 |
| 66 | 40 | 4 | 4 | 1 |
| 67 | 40 | 3 | 4 | 1 |
+-----------+---------+--------+-------------+-------------+
To get the number of boards, and Board_ID, ran during a given period I query.
SELECT a.Board_ID FROM
Tests a, Results b
WHERE a.Date_Time>='2017-08-02' AND a.Date_Time<'2017-08-03' and
a.Test_ID = b.Test_ID
group by a.Board_ID
To get all associated test to those Board_ID's I query.
SELECT * from
Tests x, (
SELECT a.Board_ID FROM
Tests a, Results b
WHERE a.Date_Time>='2017-08-02' AND a.Date_Time<'2017-08-03' and
a.Test_ID = b.Test_ID
group by a.Board_ID
) y
where x.Board_ID = y.Board_ID
This gives me the correct results, but the query seems off, but when I try to get the failed results from the query above is when I have the most trouble.
SELECT d.Test_ID FROM
Boards a, Tests b, (
SELECT x.Test_ID, x.Board_ID, x.Operator, x.Date_Time from
Tests x, (
SELECT a.Board_ID FROM
Tests a, Results b
WHERE a.Date_Time>='2017-08-02' AND a.Date_Time<'2017-08-03' and
a.Test_ID = b.Test_ID
group by a.Board_ID
) y
)d
WHERE d.Test_ID = b.Test_ID and
b.Result not between Lower_Limit and Upper_Limit
EDIT:
If you look at the Test table I created you will see that board_id 3 got tested twice and on two different days. I need to see the boards that we ran on a given day, this example 2017-08-02, and all associated records to those boards. So since Board_ID #3 was ran on 2 days, and was ran on the day in question, I would need that record included in my query.
My Solution
SELECT * FROM
(
SELECT x.Test_ID, x.Board_ID, x.Operator, x.Date_Time from
Test x, (
SELECT a.Board_ID FROM
Test a
join Results b on a.Test_ID = b.Test_ID
WHERE a.Date_Time>='2017-08-11' AND a.Date_Time<'2017-08-12'
group by a.Board_ID
) y
where x.Board_ID = y.Board_ID
)d
join Boards a on a.Board_ID = d.Board_ID
join Results b on b.Test_ID = d.Test_ID
join Test_Names c on c.Test_Name_ID = b.Test_Name_ID --Table Not shown
WHERE
b.result not between Lower_Limit and Upper_Limit
From this you see I have 3 nested searches into 1. With the 3 individual searches I get all the data I need to parse the information I want. Next will be to find a way to query the database for what I need instead of parsing.
I think you're overthinking this. You don't need all the inline views. Here's how I would write it using ANSI Joins (like #CptMisery suggested in the comments)
SELECT d.test_id, b.board, b.board_rev, r.result_id, r.result -- and whatever else you need.
from tests t
join results r on t.test_id = r.test_id
join boards b on t.board_id = b.board_id
where t.Date_Time>='2017-08-02' AND t.Date_Time<'2017-08-03'
and r.result >Lower_Limit -- or >=
and r.result < Upper_Limit -- or <=, if it can be the limit value
JOIN all the tables based on their relationships (Foreign Key to Primary Key), choose your filters in the where clause, and choose the columns to "project" with Select.
SELECT d.Test_ID FROM
Boards a, Tests b, ( SELECT x.Test_ID,
x.Board_ID,
x.Operator,
x.Date_Time
from Tests x,
(SELECT a.Board_ID
FROM Tests a, Results b
WHERE a.Date_Time>='2017-08-02'
AND a.Date_Time<'2017-08-03'
and a.Test_ID = b.Test_ID
group by a.Board_ID
) y
)d
WHERE d.Test_ID = d.Test_ID
and b.Result >= Lower_Limit
and b. Result <=Upper_Limit
How can I write a single query that will give me SUM(Entrance.quantity) - SUM(Buying.quantity) group by product_id.
The problem is in rows that not exist in the first or second table. Is possible to do this?
Entrance:
+---+--------------+---------+
| id | product_id | quantity|
+---+--------------+---------+
| 1 | 234 | 15 |
| 2 | 234 | 35 |
| 3 | 237 | 12 |
| 4 | 237 | 18 |
| 5 | 101 | 10 |
| 6 | 150 | 12 |
+---+--------------+---------+
Buying:
+---+------------+-------------+
| id | product_id | quantity|
+---+------------+-------------+
| 1 | 234 | 10 |
| 2 | 234 | 20 |
| 3 | 237 | 10 |
| 4 | 237 | 10 |
| 5 | 120 | 15 |
+---+------------+------------+
Desired result:
+--------------+-----------------------+
| product_id | quantity_balance |
+--------------+-----------------------+
| 234 | 20 |
| 237 | 10 |
| 101 | 10 |
| 150 | 12 |
| 120 | -15 |
+--------------+-----------------------+
This is tricky, because products could be in one table but not the other. One method uses union all and group by:
select product_id, sum(quantity)
from ((select e.product_id, quantity
from entrance e
) union all
(select b.product_id, - b.quantity
from buying b
)
) eb
group by product_id;
SELECT product_id ,
( Tmp1.enterquantity - Tmp2.buyquantity ) AS Quantity_balance
FROM entrance e1
CROSS APPLY ( SELECT SUM(quantity) AS enterquantity
FROM Entrance e2
WHERE e1.product_id = e2.product_id
) Tmp1
CROSS APPLY ( SELECT SUM(quantity) AS buyquantity
FROM Buying b2
WHERE e1.product_id = b2.product_id
) Tmp2
GROUP BY Product_id,( Tmp1.enterquantity - Tmp2.buyquantity )
I have table with a bunch of (machine id) mid's and (sensor id) sid's, and their corresponding (values) v's. Needless to say the id column is a unique row number. (NB: There are other columns in the table, and not all mid's have the same sid's)
Current Table:
+------+-------+-------+-----+---------------------+
| id | mid | sid | v | timestamp |
+------+-------+-------+-----+---------------------+
| 51 | 10 | 1 | 40 | 2015/5/1 11:56:01 |
| 52 | 10 | 2 | 39 | 2015/5/1 11:56:25 |
| 53 | 10 | 2 | 40 | 2015/5/1 11:56:42 |
| 54 | 11 | 1 | 50 | 2015/5/1 11:57:52 |
| 55 | 11 | 2 | 18 | 2015/5/1 11:58:41 |
| 56 | 11 | 2 | 19 | 2015/5/1 11:58:59 |
| 57 | 11 | 3 | 58 | 2015/5/1 11:59:01 |
| 58 | 11 | 3 | 65 | 2015/5/1 11:59:29 |
+------+-------+-------+-----+---------------------+
Q: How would I get the MAX(v)for each sid for each mid?
Expected Output:
+------+-------+-------+-----+---------------------+
| id | mid | sid | v | timestamp |
+------+-------+-------+-----+---------------------+
| 51 | 10 | 1 | 40 | 2015/5/1 11:56:01 |
| 53 | 10 | 2 | 40 | 2015/5/1 11:56:42 |
| 54 | 11 | 1 | 50 | 2015/5/1 11:57:52 |
| 56 | 11 | 2 | 19 | 2015/5/1 11:58:59 |
| 58 | 11 | 3 | 65 | 2015/5/1 11:59:29 |
+------+-------+-------+-----+---------------------+
The expected output is to obtain the whole row with all the (single) max value for all the sids in all the mids.
Addendum:
Due to a very big table, I need to place boundaries with dates. For the sample above the two boundary dates should be 2015/05/01 00:00:00 (1st of May'15) till 2015/05/02 00:00:00 (2nd of May'15). Q: How could I add this date boundary?
Find the max v in subquery for each combination of mid, sid and then join it with your original table to get the desired result.
select *
from your_table t
join (
select mid, sid, max(v) as v
from your_table
group by mid, sid
) t2 using (mid, sid, v);
Note here that if there are multiple rows with same sid, mid and v, it will return all of them.
As mentioned in the comments, since you have an id column, you can include that in limited correlated query like this:
select *
from your_table t1
where id = (select id
from your_table t2
where t1.mid = t2.mid
and t1.sid = t2.sid
order by v desc, id desc
limit 1
);
This will give you one single row per mid, sid combination with max v (and latest id in case of ties).
Use MAX() function with GROUP BY clause
SELECT id, mid, sid, MAX(v) AS v, `timestamp`
FROM MyTable
GROUP BY mid, sid;
This returns rows with maximum values of v for each combination of mid and sid.
i have following scheme,
purchase_order
+-------------------+----------------------+
| purchase_order_id | purchase_order |
+-------------------+----------------------+
| 54 | Purchase Order 12345 |
| 56 | po-laptop-hp-3 |
| 57 | po-laptop-hp-1 |
+-------------------+----------------------+
purchase_order_detail
+--------------------------+-------------------+---------+------------------+
| purchase_order_detail_id | purchase_order_id | item_id | ordered_quantity |
+--------------------------+-------------------+---------+------------------+
| 61 | 54 | 279 | 500 |
| 62 | 54 | 286 | 700 |
| 63 | 56 | 279 | 43 |
| 64 | 57 | 279 | 43 |
| 65 | 57 | 286 | 43 |
| 66 | 57 | 287 | 43 |
+--------------------------+-------------------+---------+------------------+
delivery_order
+-------------------+--------------------------+-------------------+
| delivery_order_id | purchase_order_detail_id | recieved_quantity |
+-------------------+--------------------------+-------------------+
| 62 | 61 | 250 |
| 63 | 62 | 300 |
| 64 | 63 | 34 |
| 65 | 64 | 34 |
| 66 | 65 | 34 |
| 67 | 66 | 34 |
| 68 | 61 | 34 |
| 69 | 61 | 34 |
+-------------------+--------------------------+-------------------+
stock
+----------+-------------------+------------+----------+------------------+---------------+
| stock_id | delivery_order_id | project_id | quantity | initial_quantity | stock_type_id |
+----------+-------------------+------------+----------+------------------+---------------+
| 12 | 62 | 1 | 60 | 60 | 1 |
| 13 | 63 | 1 | 120 | 120 | 1 |
| 14 | 63 | 1 | 50 | 50 | 1 |
| 15 | 64 | 1 | 12 | 12 | 1 |
| 16 | 62 | 1 | 120 | 120 | 1 |
| 17 | 62 | 1 | 12 | 12 | 1 |
+----------+-------------------+------------+----------+------------------+---------------+
i have write this query but it returns duplicate results
SELECT po.created_on
, po.purchase_order
, i.item_name
, u.unit_name
, pod.ordered_quantity
, do.recieved_quantity
, do.recieved_on
, po.remarks
FROM purchase_order po
, purchase_order_detail pod
, delivery_order do
, stock s
, item i
, unit u
WHERE u.unit_id = i.unit_id
AND i.item_id = pod.item_id
AND po.purchase_order_id = pod.purchase_order_id
AND pod.purchase_order_detail_id = do.purchase_order_detail_id
AND do.delivery_order_id = s.delivery_order_id
AND s.project_id = 1
ORDER BY po.purchase_order_id
, pod.item_id
;
The results
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
| created_on | purchase_order | item_name | unit_name | ordered_quantity | recieved_quantity | recieved_on | remarks |
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
| 2015-02-24 22:48:15 | Purchase Order 12345 | HP Laptops | Unit | 500 | 250 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | HP Laptops | Unit | 500 | 250 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | Lenovo | Unit | 700 | 300 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | Lenovo | Unit | 700 | 300 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:55:40 | po-laptop-hp-3 | HP Laptops | Unit | 43 | 34 | 2015-02-21 00:00:00 | dfgsdfgsd |
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
relationship is one to many from top to bottom.
What I wanted to get is the each purchase_order , his ordered quantity of each item, and total recieved quantity, and quantity in stock where project_id = 1 from stock.
i am expecting something like this,
+-------------------+---------+------------------+---------------+----------+
| purchase_order_id | item_id | ordered_quantity | totalReceived | quantity |
+-------------------+---------+------------------+---------------+----------+
| 54 | 279 | 500 | 314 | 192 |
| 54 | 286 | 700 | 300 | 170 |
| 56 | 279 | 43 | 34 | 12 |
+-------------------+---------+------------------+---------------+----------+
EDIT
Thank you for clearing up the mistake in my first part. I realize now that we cannot do all calculations in a single query (because we group on different columns in various parts) so I started by writing individual subqueries and joining them together. The steps went something like this:
Get the sum of received total received quantity for each
purchase_order_detail_id from the delivery_order table.
Join that subquery with the delivery_order table itself to get the totalReceived for the various delivery_order_id values.
Join that result set with the purchase_order_detail table to get the purchase_order_id, item_id, and ordered_quantity for each delivery_order_id.
We now have a result set including the delivery_order_id, purchase_order_id, item_id, ordered_quantity, and total received. The last two things are:
Get the SUM() of quantity for each delivery_order_id from the stock table.
Join that with our above result set on the condition that order_id matches (so we will only get one row) and that project_id is 1 (so we only get the necessary delivery_order_id values). I put that condition in the WHERE clause of the sum subquery.
Here is your final query:
SELECT tmp1.purchase_order_id, tmp1.item_id, tmp1.ordered_quantity, tmp1.totalReceived, tmp2.quantity
FROM(
SELECT tmp.delivery_order_id, pod.purchase_order_id, pod.item_id, pod.ordered_quantity, tmp.totalReceived
FROM purchase_order_detail pod
JOIN(
SELECT do.delivery_order_id, tmp.purchase_order_detail_id, tmp.totalReceived
FROM delivery_order do
JOIN(
SELECT do.purchase_order_detail_id, SUM(do.received_quantity) AS totalReceived
FROM delivery_order do
GROUP BY do.purchase_order_detail_id) tmp ON tmp.purchase_order_detail_id = do.purchase_order_detail_id)
tmp ON tmp.purchase_order_detail_id = pod.purchase_order_detail_id) tmp1
JOIN(
SELECT s.delivery_order_id, SUM(quantity) AS quantity
FROM stock s
WHERE s.project_id = 1
GROUP BY s.delivery_order_id) tmp2 ON tmp2.delivery_order_id = tmp1.delivery_order_id;
Here is the SQL Fiddle. It shows all of the intermediate steps too, if you'd like to see how the results came together individually.
Try modifying your query to use DISTINCT and OUTER JOINs instead of cartesian ("comma") joins.
SELECT DISTINCT po.created_on
, po.purchase_order
, i.item_name
, u.unit_name
, pod.ordered_quantity
, do.recieved_quantity
, do.recieved_on
, po.remarks
FROM purchase_order po
LEFT JOIN purchase_order_detail pod USING (purchase_order_id)
LEFT JOIN delivery_order do USING (purchase_order_detail_id)
LEFT JOIN stock s USING (delivery_order_id)
LEFT JOIN item i USING (item_id)
LEFT JOIN unit u USING (unit_id)
ORDER BY po.purchase_order_id
, pod.item_id
;