MySQL query, finding from one table and insert into second table - mysql

I am looking for the following:
Need the row with this condition: Common values of Device columns AND first three chars of Interface column from both tables.
Then the row which matched the above condition from Table1, retrieve the value of Specified column and store it in the Avgin column of the Table2 in the row where above condition matched.
Can someone help me with it? Database is MySQL.

If there are more than one matches, only the first one will be used.
If there are none, null will be used. If you would like something else, use ifnull().
UPDATE
table2
SET
avgin=ifnull(
(
SELECT
Specified
FROM
table1
WHERE
table1.Device=table2.Device
AND substring(table1.Interface,1,3)=substring(table2.Interface,1,3)
LIMIT 1
),
'default value'
)
edit: added the ifnull()

UPDATE with JOIN is what you need here, something like this:
UPDATE Table2 AS t2
INNER JOIN table1 AS t1 ON LEFT(t2.Interface, 3) = LEFT(t1.Interface, 3)
AND t1.Device = t2.Device
SET t2.Avgin = t1.specified;
With the JOIN condition, as you explained in your question:
LEFT(t2.Interface, 3) = LEFT(t1.Interface, 3)
AND
t1.Device = t2.Device
LEFT will give you the first 3 chars from the left of both table.
See it in action here:
SQL Fiddle Demo
This will make the table2 looks like:
| CID | DEVICE | INTERFACE | AVGIN |
---------------------------------------------------
| HDC-HKG-R01 | HDC-TBONE-P1 | P09/0/0 | 121.36 |
| OCB-OCD-R01 | OCB-PE1 | Gi5/2 | 0.17 |
| HDC-BSA-R01 | HDC-TBONE-P1 | Se9/2/0 | (null) |

Use this to confirm you're getting the rows you're expecting (ie BEFORE updating anything):
SELECT
t1.Specified
FROM
table2 t2
INNER JOIN table1 t1
ON t1.device = t2.device
AND LEFT(t1.interface,3) = LEFT(t2.interface,3)
And then, assuming that's right:
UPDATE table2 t2
INNER JOIN table1 t1
ON t1.device = t2.device
AND LEFT(t1.interface,3) = LEFT(t2.interface,3)
SET t2.Avgin = ifnull(t1.specified,'Default Value For When t1.Specified is NULL')
Note we're using an INNER join... that means that rows from table2 that have no corresponding row in table1, are discarded from the results (which is what you want).
The IFNULL will allow you to use a default value in the case when your join succeeds (because device and first three chars of interface are common to both tables), but table1.specified has a NULL value for that row.

Related

sql: select rows which have the same column value in another column with a single query

example table:
id | value
----------
1 | abc
1 | cb3
1 | dsf
2 | sss
2 | d3
So if the input is "cb3" I want to get all rows with id 1, if the input is "sss" I want to get all rows with id 2. Can this be done with one query instead of two ? (first query is find id and second query bring rows for found id). Also, would a one query approach be faster ?
Thank you in advance.
you could try this :
SELECT *
FROM TABLE my_table
WHERE id IN (SELECT id
FROM TABLE my_table
WHERE value = input
)
Try the following, where you replace 'sss' with the value you are searching for:
select * from table t1
where t1.id in (select id from table t2 where value = 'sss')
Note that value seems not to be a key, such that you might get two different groups of ids in your result. That's also the reason why I proposed an t1.id IN (select id ... rather than an t1.id = (select id ....
You can solve it using inner join also.
SELECT S.*
FROM dataset AS S
INNER JOIN dataset AS T
ON S.id = T.id
WHERE T.value = 'cb3';

How do I create a relation between tables using an interval comparison in MySQL?

I would like to create a relationship between two tables based on whether a value in one table falls in a an interval in the other. One table 1 is ~16000 rows:
name | start | end
-----------------------------------------
someName | startPosition | endPosition
table 2 is ~20000000 rows:
id | location
--------------------------
someID | positionInteger
Each id falls in the interval of exactly one name, but each name can have many ids associated with it.
I would like to add a new index to table 2 so that it becomes:
id | location | name
---------------------------------
someID | positionInteger | someName
I've tried doing:
ALTER TABLE table2 ADD INDEX name (name);
With a bit of python I can get all the names in the database and then for each name and interval:
SELECT someID FROM table2 WHERE location >= startPosition AND location <= endPosition
Then I can loop through the resulting IDs and:
UPDATE table2 SET name = 'someName' WHERE id = 'someID'
This works but is very slow. Is there a more efficient way to do this using MySQL and avoiding multiple loops?
Join the tables
SELECT t2.id, t2.location, t1.name
FROM Table1 AS t1
JOIN Table2 AS t2 ON t2.location BETWEEN t1.startPosition AND t1.endPosition
You shouldn't be adding an index to table 2, you should be adding a column:
ALTER TABLE Table2 ADD COLUMN name VARCHAR(32); -- Replace this with the actual size
Then you can update all the rows with a similar join:
UPDATE Table2 AS t2
JOIN Table1 AS t1 ON t2.location BETWEEN t1.startPosition AND t1.endPosition
SET t2.name = t1.name
You can use LEFT JOIN :
SELECT id,location,name FROM table2 as t2
LEFT JOIN table1 as t1
ON t2.location BETWEEN t1.`start` AND t1.`end`;
More details http://sqlfiddle.com/#!9/721e5/1

mySQL combining two tables I get more results

I have one table of like this
user|itemID
and another table like this:
itemID | itemTrait1 | itemTrait2 etc...
I am trying to link the tables in one query which should be simple. I conduct the query like so:
SELECT * FROM Table1, Table2 WHERE Table1.userID = 1 AND Table1.itemID = Table2.itemID;
The issue is that I am getting 456 results returned but if I simply run:
SELECT * FROM Table1 WHERE userID = 1;
I get 434 results. Should both these statements get the same number of results returned?
How I imagine this call working is that for every entry in Table 1 for user 1 it connects it to the item's data in Table2? I think I am missing something here.
Query to combine both tables based in itemID
select * from table1 t1
left join table t2 on t1.itemID = t2.itemID
where t1.itemID = 1;
if you are getting the more records than the records that of table1 then your second table table2 must have multiple records for itemID. for example
Table1
user | itemId
---------------
1 | 1
Table2
itemId | itemTrait1 | itemTrait2
----------------------------------------
1 | A | B
1 | C | D
now when you will apply join here it will join itemID 1 with two items of second table.

sql - inner join performing cross join

I have the following table structure.
create table t1 (
id int,
tno int
);
create table t2 (
id int,
detailno int
);
insert into t1 values (101,1);
insert into t1 values (101,2);
insert into t2 values (101,7);
insert into t2 values (101,8);
When I perform the following query:
select * from t1
inner join t2
on t1.id = t2.id
where t2.detailno = 8;
It performs a cross join and returns
id | tno | id | detailno
101 | 1 | 101 | 8
101 | 2 | 101 | 8
It is basically performing a Cross join instead of an inner join. Could you please help me return only a single result instead - since detail id = 8 is in the where clause ? I have shortened the table structure and the query for easier understanding. Here is the sql fiddle for the above code. http://sqlfiddle.com/#!9/92c98/1
Your query is doing exactly as you've asked it to do.
What is the one result you're expecting?
If you only want one line then maybe you're better off making the query more specific by adding a condition such as
WHERE t2.detailno = 8
AND t1.tno = 1
which will whittle down the results more.
Edit
If you're unsure what the value of t1.tno is going to be then could you not pass that in as a parameter? It might be more clear if you can explain why you're expecting t1.tno = 2.
You'd then potentially end up with something like this if you pass it in as a parameter.
WHERE t2.detailno = 8
AND t1.tno = #tno
Join is working as expected.
Execute this to check:
select * from t1
inner join t2
on t1.id = t2.id;
Every id is making join with another table's id and which is correct for join.
So if you want result as your expectation you need to pass t1.tno and add into where condition as there are multiple record in another table for same id (t1.id).

Merge values in sql rows

I am looking for ways to merge row values into one row where the column to merge is the same
Transform:
FK | F1
========
3 | ABC
3 | DEF
to
FK | F1 | F2
=================
3 | ABC | DEF
Update:
I initially don`t know the values of F1. They might be everything, but I know they are unique for a given FK and they are varchars.
Update 2:
With your help I came to this query that will also add the FK for which there is only one value. I suppose it could be improved.
SELECT IFNULL(jointable.FK,table.FK) AS FK, IFNULL(jointable.F1,table.F1), jointable.F2
FROM table
LEFT JOIN
(SELECT T1.FK, T1.F1, T2.F1 AS F2
FROM table T1
LEFT JOIN table T2 ON T1.FK = T2.FK
WHERE T1.F1 <> T2.F1
GROUP BY T1.FK
) as jointable
ON table.FK=jointable.FK
GROUP BY FK;
Try this
SELECT FK
, T1.F1
, T2.F1 AS F2
FROM table T1
LEFT JOIN table T2 ON T1.FK = T2.FK AND T1.F1 <> T2.F1 --Criteria moved here
The LEFT JOIN is used since you mentioned that you have 1 or more values, which means the INNER JOIN could end up excluding rows.
The second criteria is to make sure you don't en up with rows like:
FK | F1 | F2
=================
3 | ABC | ABC
Please be aware that in case of an OUTER JOIN (either LEFT or RIGHT) the join criteria is not the same as the filter criteria, and therefore I moved it above.
In SQL Server, you can use ROW_NUMBER() over FK, maybe with an ORDER BY.
In MySQL you might be able to use it with a GROUP BY as you mentioned in comments, I am not sure it will work (at least not in SQL Server without an aggregate function or a CTE).
Here is a live test: http://ideone.com/Bu5aae
A suggestion:
SELECT FK, CONCAT(T1.F1,'',T2.F1) AS Result
FROM table T1, table T2
WHERE T1.FK = T2.FK