I need to extract multiple rows that are associated with each while not knowing which are.
Say I have three columns
ID | Start | End
---------------------------
1 | A | B
2 | B | C
3 | B | D
4 | C | D
5 | C | A
I want to exact all the rows that build a graph from A to D.
But I don't know the intermediate letters between A and D or I know it has to pass by C (which in this case would be ID 1,2,4 and not 1,3).
Is there a way to do this without going to a full blown graph database? (I will at a later stage, but for now I'm stuck with MySQL)
Related
I have four tables. The first describing a mix of items. The second is a linking table between the mix, and the items. The third is the item table, and the fourth holds lot information - lot number, and when that lot starts being used.
mix
mixID | mixName
----------------
1 | Foxtrot
2 | Romeo
mixLink
mixID | itemID
----------------
1 | 1
1 | 2
1 | 3
item
itemID| itemName
----------------
1 | square
2 | triangle
3 | hexagon
itemLots
itemID| lotNo | startDate
-------------------------
1 | 22/5/3| 22/07/16
2 | 03/5 | 25/07/16
2 | 04/19 | 12/08/16
3 | 15/0 | 05/08/16
Now, I need to be able to fetch the information from the database, which details all the items from a mix, as well as the most recently used lot number, something like this:
itemName | lotNo
----------------
square | 22/5/3
triangle | 04/19
hexagon | 15/0
I've tried a dozen different mixes of joins, group by's, maxes, subqueries, and havings; all to no avail. Any help would be much appreciated, I've been pulling my hair out for hours, and I feel like my fingernails are just scraping at the solution!
This will give you the result you're after and will perform pretty well if you have your indexes done properly. I'm not sure how you're meaning to reference mix as it's not apparent in your sample output but I've included it in the WHERE clause so hopefully you can understand where you would use it.
SELECT i.itemName
, (SELECT il.lotNo FROM itemLots il
WHERE il.itemID=i.itemID
ORDER BY il.startDate desc
LIMIT 1) as lotNo
FROM item i
JOIN mixLink ml ON ml.itemID=i.itemID
JOIN mix m ON m.mixID=ml.mixID
WHERE m.mixName="Foxtrot";
I have a problem, I would like to write a MySql query to achieve the result below:
Id | C1 | C2 | Score | Q | CCount | RF |
1 | A | B | 0.25 | 40 | 4 |
2 | A | B | 0.60 | 40 | 4 |
3 | A | C | 0.10 | 20 | 2 |
4 | A | B | 0.90 | 40 | 4 |
5 | A | C | 0.30 | 20 | 2 |
6 | A | B | 0.70 | 40 | 4 |
The CCount column is the total number of rows per combination ie AB, AC etc..
In the table the above ABs have a total count of 4 rows while the ACs have a total count of 2 rows.
Should I use 2 tables? The Main table and a count table and then, insert count result back into the main table using group by etc.. If so, how would I go about it?
Is there another way of solving my problem?
This part below, I can do:
I am doing this because I would like to calculate RF (Relative Frequency) of each row.
RF = Score * Q/CCount
I'm pretty sure you are doing this wrong (as I cant see the whole problem).
Just tested this now, you can do this in query.
select count(CONCAT(C1,C2)) as count, CONCAT(C1,C2) as name from data group by C1,C2
output is
count combo
4 AB
2 AC
From here you should be able to get the RF as I have got the totals.
To make things simple you can now do a 2nd query running through the rows and calculating the score.
Its possible that you could do a subquery. But that is getting really tricky.
John.
I would like to be able to track lifetime events of certain item and to be able to reconstruct its state at any time in the past for vizualization purposes. "State" here means a snapshot of several parameters, e.g. location, temperature and being alive/dead. Raw parameter values are recorded/entered only "on change" and independent from each other.
How should I store the parameter change events to be able to reconstruct the state later?
I can think of two possible solutions:
Solution 1: "Snapshot" table
+----------+-------------+------+------+
| Location | Temperature | Dead | Time |
+----------+-------------+------+------+
| A | + | 0 | 001 |
+----------+-------------+------+------+
| A | - | 0 | 002 |
+----------+-------------+------+------+
| B | + | 0 | 005 |
+----------+-------------+------+------+
On parameter change the state itself is updated and stored. To get a state of an item at a certain point is as simple as fetching one row.
This is exactly what I need, except:
Redundant data, all parameters are recorded even if only one has changed at the time
Table has to be altered if attribute set changes in the future
Knowing when a certain parameter changed is impossible without row comparison
Solution 2: Recording events
table stores individual parameters/changes rather than a complete shapshot.
+----+-----------+------------+------+
| ID | EventType | EventValue | Time |
+----+-----------+------------+------+
| 1 | loc | A | 001 |
+----+-----------+------------+------+
| 2 | temp | + | 001 |
+----+-----------+------------+------+
| 3 | temp | - | 002 |
+----+-----------+------------+------+
| 4 | loc | B | 005 |
+----+-----------+------------+------+
| 5 | temp | + | 005 |
+----+-----------+------------+------+
While this solution is more flexible than the first, it is problematic to reconstruct the snapshot. For example, how to efficiently check what is the temperature, location and viability at a time 004 in as few DB queries as possible?
Are there other solutions for this problem?
(P.S. This is for a biology experiment web app using php+Doctrine2+MySQL)
Using your Solution 2 you can very easy get everything you need:
SELECT DISTINCT (t1.eventType),t1.eventValue, t2.*
FROM `events` AS t1
LEFT JOIN
(SELECT eventtype, max(time) AS time
FROM events
WHERE events.`time`<='004'
GROUP BY eventtype ) AS t2
ON t1.eventType=t2.eventType
WHERE t1.time=t2.time
so this query will return all different attribute that was valid for time 004 , and you will see when each of attribute was set
Your second solution is looking pretty solid. There are other ways to organize the data, such as an field level revision table, which is a touch more structure than you currently have.
Using the second solution you could get a snapshot in one query with a sub-query. I assume this is something that "just needs to be done" and doesn't rely on the most efficient query.
SELECT * FROM (
SELECT * FROM event
WHERE time >= '003'
ORDER BY Time DESC) AS temp
GROUP BY EventType;
For the sake of simplicity in explaining this, imagine a room full of people talking to each other. Every statement made by one person to another would be a record in this table, and all of these records have a unique ID assigned through auto-increment.
However, not everyone in this room is talking to everyone else. There's multiple conversations going on.
These conversations need to be unique amongst themselves. This would prevent a duplicate conversation ID being started, and the site collecting all statements which don't belong to that person.
Or, in graphical representation:
----------------------------------------------
| MessageID | ConvoID | Sender | Recipients | etc...
----------------------------------------------
| 1 | 1 | A | B |
----------------------------------------------
| 2 | 1 | B | A |
----------------------------------------------
| 3 | 2 | C | D |
----------------------------------------------
| 4 | 1 | A | B |
----------------------------------------------
| 5 | 2 | D | C |
----------------------------------------------
| 6 | 1 | B | E |
----------------------------------------------
| 7 | 3 | E | F |
----------------------------------------------
You can actually see the conversations that are taking place here... A talked to B (ID 1), who replied back (ID 2) at around the same time C started a new conversation (CID 2) with D (ID 3).
A finally gets back to B about something (ID 4) and D eventually response to C's earlier inquiry (ID 5). B then talks to E about the same thing he was talking with A about (CID 1) before E turns right around and connects with F to start a completely new conversation.
If this has read like the steps which occur prior to the immediate termination of an employee, it wasn't intended that way, but you're not alone.
So you can see that every DB entry has a unique ID (MessageID), but these messages need to be easily collated together.
The solution I'm seeking is something that allows the DB to create a new and unique "ConvoID". This is why we can't auto-increment, or why we can't force uniqueness on the data set. Duplicates must occur, by nature of what this column is doing, but auto-increment would do, perhaps, the exact opposite of what it is i'm seeking for.
Any help that could point me in the right direction would be significantly appreciated.
Thanks!
You could normalize the design by adding a Conversations table. The table would have its own auto-incrementing column. Whenever a new conversation is started, you add a row to Conversations, and use its identifier as ConvoID.
I have a comma delimited list that im storing in a varchar field in a mysql table.
Is it possible to add and remove values from the list directly using sql queries? Or do I have to take the data out of the table, manipulate in PHP and replace it back into mysql?
There is no way to do it in InnoDB and MyIsam engines in mysql. Might be in other engines (check CSV engine).
You can do it in a stored procedure, but, not recommended.
What you should do to solve such an issue is to refactor your code and normalize your DB =>
original table
T1: id | data | some_other_data
1 | gg,jj,ss,ee,tt,hh | abanibi
To become:
T1: id | some_other_data
1 | abanibi
T2: id | t1_id | data_piece
1 | 1 | gg
2 | 1 | jj
3 | 1 | ss
4 | 1 | ee
5 | 1 | tt
6 | 1 | hh
and if data_piece is a constant value in the system which is reused a lot, you need to add there a lookup table too.
I know it looks more work, but then it will save you issues like you have now, which take much more time to solve.