Merging Corresponding MySQL Records - mysql

I have a MySQL table called "objecttable" that has the following structure and data in it. (The data is just a sequence, there is a whole lot more).
ID | Name | posX | posY | posZ |rotX | rotY | rotZ | rotW |
3562 | LODpmedhos1_LAe | 2062 | -1703 | 16 | 0 | 45 | 22 | 1 |
3559 | LODpmedhos5_LAe | 2021 | -1717 | 15 | 0 | 45 | 34 | 1 |
3561 | LODpmedhos3_LAe | 2021 | -1717 | 15 | 0 | 45 | 34 | 1 |
I want to figure out which records have the same posX, posY, posZ, rotX, rotY and rotZ values and insert them into a table called "matchtable", and in the end I want it to look like this (I have the table structure ready)
ID1 | Name | ID2 | Name |
3559 | LODpmedhos5_LAe | 3561 | LODpmedhos3_LAe|
I'd appreciate if someone could give me the correct SQL query for it. I don't have more than two matching coordinates and not all coordinates match.
Sorry if the table representations suck, I'll try to make a HTML table if necessary.
Thanks!

This query will do the trick, but the number of results might be a LOT more than required. For example, if there are 5 rows satisfying your query, then the results will be 20( = n*(n-1) ) in number.
SELECT ot.ID AS ID1, ot.Name AS Name1, ot2.ID AS ID2, ot2.Name AS Name
FROM objecttable ot
JOIN objecttable ot2
ON ot.ID > ot2.ID
AND ot.posX = ot2.posX
AND ot.posY = ot2.posY
AND ot.posZ = ot2.posZ
AND ot.rotX = ot2.rotX
AND ot.rotY = ot2.rotY
AND ot.rotZ = ot2.rotZ
EDIT
In reply to lserni's comment:
ON ot.ID <> ot2.ID
The above condition is there to remove the result like:
ID1 | Name | ID2 | Name |
3559 | LODpmedhos5_LAe | 3559 | LODpmedhos5_LAe|

try this:
-- insert into matchtable -- uncomment to insert the data
select alias1.Id,
alias1.Name,
alias2.Id
alias2.Name
from objecttable as alias1
join objecttable as alias2
on alias1.posx = alias2.posx
and alias1.posy = alias2.posy
and alias1.posz = alias2.posz
and alias1.roty = alias2.roty
and alias1.roty = alias2.roty
and alias1.rotz = alias2.rotz
and alias1.Id > alias2.Id

Related

Combining three SQL queries into one

I got working code from three queries but I would like to combine them into one or two. Basically I am checking if a provided phone number exists in table contacts or leads as well as if it exists as a secondary number in customfieldsvalues (not all leads have a customfield value though). I am using a CRM system based on CodeIgniter.
What I want to do (non-correct/hypothetical query):
SELECT * FROM contacts OR leads WHERE phonenumber = replace(X, '-', '')
OR leads.id = customvaluefields.relid AND cfields.fieldid = 41 AND cfields.value = X
Tables
table : contacts
+-------+----------------+----------------+
| id | firstname | phonenumber |
+-------+----------------+----------------+
| 1 | John | 214-444-1234 |
| 2 | Mary | 555-111-1234 |
+-------+----------------+----------------+
table : leads
+-------+-----------+---------------------+
| id | name | phonenumber |
+-------+-----------+---------------------+
| 1 | John | 214-444-1234 |
| 2 | Mary | 555-111-1234 |
+-------+-----------+---------------------+
table : customvaluefields
+-------+-----------+-------------+-----------+
| id | relid | fieldid | value |
+-------+-----------+-------------+-----------+
| 1 | 1 | 41 | 222333444 |
| 2 | 1 | 20 | Management|
| 3 | 2 | 41 | 333444555 |
+-------+-----------+-------------+-----------+
If I understand what you are trying to, maybe UNION ALL would work. This is something to get you started:
SELECT C.ID, C.FirstName, C.Phonenumber
FROM Contacts C
JOIN CustomValueField CVF
ON c.ID = CVF.RelID AND
CVF.ID = 41
AND REPLACE(Phonenumber,'-','') = cvf.Value
UNION ALL
SELECT L.ID, L.FirstName, L.Phonenumber
FROM Leads L
JOIN CustomValueField CVF
ON L.ID = CVF.RelID AND
CVF.ID = 41
AND REPLACE(Phonenumber,'-','') = cvf.Value
I'm joining the contacts and leads tables to CustomeValueField in each query and then UNION them together along with the WHERE clause in each. I'm sure it's not 100% correct for what you need, but should get you headed to a solution. Here is more information: https://dev.mysql.com/doc/refman/8.0/en/union.html

MySQL: SUM function applied to a formula contained in field selected by another query

I'm in the need to perform a select SUM() where that is a formula contained into a field selected by another query.
Example:
table_A (the "formula" field contains, in each cell, an arithmetic expression involving columns from table B):
+------------+--------------+------------+
| Product_id | related_prod | formula |
+------------+--------------+------------+
| U1 | C2 | col2-col1 |
| U2 | C3 | col3-col2 |
| U3 | C4 | col3-col1 |
+------------+--------------+------------+
table_B:
+------------+---------+------------+----------+------+------+------+
| Product_id | year_id | company_id | month_id | col1 | col2 | col3 |
+------------+---------+------------+----------+------+------+------+
| C2 | 2017 | 1 | 2 | 100 | 200 | 300 |
| C3 | 2017 | 1 | 2 | 400 | 500 | 600 |
| C4 | 2017 | 1 | 2 | 700 | 800 | 900 |
+------------+---------+------------+----------+------+------+------+
I do, then, the following query:
SELECT
SUM(totals.relaz) as final_sum,
totals.relaz as 'col',
totals.prod as 'prod',
totals.cons as 'cons',
m.company_id, m.month_id, m.year_id, FROM `table_B` m,
( SELECT formula as relaz,
related_prod as prod,
p.product_id as cons FROM table_A p )
AS totals
WHERE m.product_id=totals.prod
GROUP BY m.company_id, m.year_id, m.month_id, m.product_id, totals.cons
After the select I'd do expect that, considering for example the only product 'U1', the corresponding row would be
+-----------+-----------+------+------+------------+----------+---------+
| final_sum | col | prod | cons | company_id | month_id | year_id |
+-----------+-----------+------+------+------------+----------+---------+
| 100 | col2-col1 | C2 | U1 | 1 | 2 | 2017 |
+-----------+-----------+------+------+------------+----------+---------+
Instead, what I get is
+-----------+-----------+------+------+------------+----------+---------+
| final_sum | col | prod | cons | company_id | month_id | year_id |
+-----------+-----------+------+------+------------+----------+---------+
| 0 | col2-col1 | C2 | U1 | 1 | 2 | 2017 |
+-----------+-----------+------+------+------------+----------+---------+
i.e. the final_sum field is always set to 0, despite the 'col' field contains the correct equation.
What am I doing wrong?
Thank you in advance
Alex
You are trying to get sum from a string column (table_A.formula). This will result 0. MySQL/MariaDB will not try to convert the strings to column references and evaluate the formula in the string.
Another thing is that you should list all columns not in aggregate function in GROUP BY.
To get the result you want, use:
SELECT
SUM(CASE
WHEN a.formula = 'col2-col1' THEN b.col2-b.col1
WHEN a.formula = 'col3-col1' THEN b.col3-b.col1
WHEN a.formula = 'col3-col2' THEN b.col3-b.col2
END
) AS final_sum,
a.formula as 'col',
a.related_prod as 'prod',
a.Product_id as 'cons',
b.company_id,
b.month_id,
b.year_id
FROM table_B b
JOIN table_A a on a.related_prod=b.Product_id
GROUP BY a.formula, a.related_prod, a.Product_id, b.company_id, b.month_id, b.year_id
It may possible to build a Stored routine that fetches the string col2-col1 and inserts it (using CONCAT) into a string, then PREPAREs and EXECUTEs the SQL string.
That is, dynamically build the SQL, perhaps like in #slaakso's Answer.
It would be messy.
I have needed something like this; I chose to do eval() in PHP, which was the client language. I use it for evaluating VARIABLES and GLOBAL STATUS. Example: Table_open_cache_misses / Uptime gives the "misses per second", which, if high, indicates the need for increasing the setting table_open_cache.

Getting the filenames record

I have case to get filenames from table foto
for the firts table
tb_induk
----------------
id_induk | nomor_induk | id_burung | hen | cock
25 | IND003 | 2 | 91442 | 30441
26 | IND004 | 2 | 10464 | 40020
note : column "hen" and "cock" is "id_data" from birds
second table:
tb_foto
----------------------
id_foto | id_data | filename
566 |91442 |4b584a8cd6cb98d4b4d9614abb223034.JPG
567 |91442 |b526318215b5c12bf79b3284d8bd5db7.JPG
568 |30441 |4db159080e0cefb4fd9a2862502ab0f5.JPG
570 |10464 |4216d01abb3bdce90bd72e40ef1d593b.JPG
571 |40020 |6c5b28bffd79fc661f44733c04d12446.JPG
The query is:
Query
-----------------------
"select
tb_induk.id_induk as id_induk,
tb_induk.nomor_induk as nomor_induk,
case WHEN tb_foto.id_data=tb_induk.Hen THEN tb_foto.filename END as filenamehen,
case WHEN tb_foto.id_data=tb_induk.Cock THEN tb_foto.filename END as filenamecock
from tb_induk INNER JOIN tb_foto ON
tb_induk.Hen=tb_foto.id_data || tb_induk.Cock=tb_foto.id_data
where id_burung=$id_burung GROUP BY tb_induk.id_induk"
Result
Result
------------------------------
id_induk | nomor_induk | id_burung | hen | cock
25 | IND003 | 2 | 4216d01abb3bdce90bd72e40ef1d593b.JPG | NULL
26 | IND004 | 2 | NULL | 207b21895c556bc5fada1ead8ec34d06.JPG
I think you can just join tb_foto twice to pull in the filenames for hens and cocks, for each tb_induk value:
SELECT t1.tb_induk,
t1.nomor_induk,
t1.id_burung,
COALESCE(tf1.filename, 'NA') AS hen,
COALESCE(tf2.filename, 'NA') AS cock
FROM tb_induk t1
LEFT JOIN tb_foto tf1
ON t1.hen = tf1.id_data
LEFT JOIN tb_foto tf2
ON t1.cock = tf2.id_data

MySql: Multiple Queries to select one column from different table

mysql> select * from SC_rules;
+--------+--------+--------+---------------+
| old_SC | new_SC | fee_JD | offer_id_Flag |
+--------+--------+--------+---------------+
| 114 | 111 | 5.000 | 1 |
| 114 | 310 | 6.000 | 1 |
| 114 | 41 | 2.000 | 0 |
+--------+--------+--------+---------------+
mysql> select * from offer_rules;
+--------+--------+----------+-------+
| old_SC | new_SC | offer_id | price |
+--------+--------+----------+-------+
| 114 | 111 | 10 | 1.000 |
| 114 | 310 | 20 | 0.500 |
+--------+--------+----------+-------+
I want the price from SC_rules where offer_id_Flag =0 and the price from offer_rules where offer_id_flag =1 in once select.
You can use a conditional LEFT JOIN to achieve this, and COALESCE to get the first non-NULL result.
Something like this (not tested):
SELECT COALESCE(o.price, sc.price)
FROM SC_rules sc
LEFT JOIN offer_rules o ON o.old_SC = sc.old_SC AND sc.offer_id_Flag = 1
Basically, get the price from your offer_rules table (if it exists) otherwise get the price from your sc_rules table (btw this column seems to be missing from your source data in your question).
The JOIN works by matching the rows on the old_SC column but you should modify this to whichever column the primary\foreign key is. The important part is the join on sc.offer_id_Flag = 1, which only makes the join when the flag value is 1 (as you want).
SELECT `fee_JD` as 'price' FROM `SC_rules` WHERE `offer_id_Flag`.`SC_rules` = '0';
SELECT `price` FROM `offer_rules` WHERE `offer_id`.`SC_rules` = '1';
If you want multi queries.

GROUP BY with aggregate and an INNER JOIN

I tried to narrow down the problem as much as possible, it is still quite something. This is the query that doesn't work the way I want it:
SELECT *, MAX(tbl_stopover.dist)
FROM tbl_stopover
INNER JOIN
(SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn
FROM tbl_edges edges1
INNER JOIN tbl_edges edges2
ON edges1.nodeB = edges2.nodeA
GROUP BY edges1.id HAVING numConn = 1) AS tbl_conn
ON tbl_stopover.id_edge = tbl_conn.id1
GROUP BY id_edge
Here is what I get:
|id | edge | dist | id1 | id2 | numConn | MAX(tbl_stopover.dist) |
------------------------------------------------------------------
|2 | 23 | 2 | 23 | 35 | 1 | 9 |
|4 | 24 | 5 | 24 | 46 | 1 | 9 |
------------------------------------------------------------------
and this is what I would want:
|id | edge | dist | id1 | id2 | numConn | MAX(tbl_stopover.dist) |
------------------------------------------------------------------
|3 | 23 | 9 | 23 | 35 | 1 | 9 |
|5 | 24 | 9 | 24 | 46 | 1 | 9 |
------------------------------------------------------------------
But let me elaborate a bit...
I have a graph, let's say as such:
node1
|
node2
/ \
node3 node4
| |
node5 node6
Therefore I have a table I call tbl_edges like this:
| id | nodeA | node B |
------------------------
| 12 | 1 | 2 |
| 23 | 2 | 3 |
| 24 | 2 | 4 |
| 35 | 3 | 5 |
| 46 | 4 | 6 |
------------------------
Now each edge has "stop_overs" at a certain distance (to nodeA). Therefore I have a table tbl_stopover like this:
| id | edge | dist |
------------------------
| 1 | 12 | 5 |
| 2 | 23 | 2 |
| 3 | 23 | 9 |
| 4 | 24 | 5 |
| 5 | 24 | 9 |
| 6 | 35 | 5 |
| 7 | 46 | 5 |
------------------------
Why this query?
Let's assume I want to calculate the distance between the stop_overs. Within one edge that is no problem. Across edges it gets more difficult. But if I have two edges that are connected and there is no other connection I can also calculate the distance. Here an example assuming all edges have a length of 10. :
edge23 has a stop_over(id=3) at dist=9, edge35 has a stop_over(id=6) at dist=5. Therefore the distance between these two stop_overs is:
dist = (length - dist_id3) + dist_id5 = (10-9) + 5
I am not sure if I made my self clear. If this is not understandable, feel free to ask question and I will do my best to make this more understandable.
MySQL allows you to do something silly - display fields in an aggregate query that are not a part of the GROUP BY or an aggregate function like MAX. When you do this, you get random (as you said) results for the remaining fields.
In your query you are doing this twice - once in your inner query (id2 is not part of a GROUP BY or aggregate) and once in the outer.
Prepare for random results!
To fix it, try something like this:
SELECT tbl_stopover.id,
tbl_stopover.dist,
tbl_conn.id1,
tbl_conn.id2,
tbl_conn.numConn,
MAX(tbl_stopover.dist)
FROM tbl_stopover
INNER JOIN
(SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn
FROM tbl_edges edges1
INNER JOIN tbl_edges edges2
ON edges1.nodeB = edges2.nodeA
GROUP BY edges1.id, edges2.id
HAVING numConn = 1) AS tbl_conn
ON tbl_stopover.id_edge = tbl_conn.id1
GROUP BY tbl_stopover.id,
tbl_stopover.dist,
tbl_conn.id1,
tbl_conn.id2,
tbl_conn.numConn
The major changes are the explicit field list (note that I removed the id_edge since you are joining on id1 and already have that field), and addition of additional fields to both the inner and outer GROUP BY clauses.
If this gives you more rows than you want then you may need to explain more about your desired result set. Something like this is the only way to ensure you get appropriate groupings.
Okay. This seems to be the answer to my question. I will do some further "investigation" though, because I'm not sure if this is reliable. If anybody has some though on this, please leave a comment.
SELECT tbl.id, tbl.dist, tbl.id1, tbl.id2, MAX(dist) maxDist
FROM
(
SELECT tbl_stopover.id,
tbl_stopover.dist,
tbl_conn.id1,
tbl_conn.id2,
tbl_conn.numConn
FROM tbl_stopover
INNER JOIN
(SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn
FROM tbl_edges edges1
INNER JOIN tbl_edges edges2
ON edges1.nodeB = edges2.nodeA
GROUP BY edges1.id
HAVING numConn = 1) AS tbl_conn
ON tbl_stopover.id_edge = tbl_conn.id1
GROUP BY tbl_stopover.dist, tbl_conn.id1
ORDER BY dist DESC) AS tbl
GROUP BY tbl.id1, tbl.id2
Thanks to JNK (my colleague at work) without whom I wouldn't have gotten this far.