Openquery insert not working - mysql

I have a linked MySQL -server to MSSQL-server and I am trying to INSERT data to the table admin_user on the MySQL -server, but end up getting the error:
Cannot process the object "dbo.admin_user". The OLE DB provider
"MSDASQL" for linked server "MYDB" indicates that either the object
has no columns or the current user does not have permissions on that
object.
This works fine:
SELECT * FROM openquery([MYDB], 'SELECT * FROM admin_user')
This gets the error:
INSERT into openquery([MYDB], 'dbo.admin_user') values ('Testi','Testaaja','me#google.com','koe','','','','','','1','N;','','')
Here are the rights of the user whom I used for creating the ODBC-connection
| xx.xxx.xxx.xx | me | *qweqweqwdq2edqdadasd|
Y | Y | Y | Y | Y |
Y | Y | Y | Y | Y | N
| Y | Y | Y | Y | Y
| Y | Y | Y | Y
| Y | Y | Y | Y
| Y | Y | Y | Y |
Y | | | |
| 0 | 0 | 0 | 0
| | NULL |
> | % | me | *asdasadasdsadasdasdsad| Y | Y | Y | Y | Y |
> Y | Y | Y | Y | Y | Y
> | Y | Y | Y | Y | Y
> | Y | Y | Y | Y
> | Y | Y | Y | Y
> | Y | Y | Y | Y |
> Y | | | |
> | 0 | 0 | 0 | 0
> | | NULL |
My catalog is bitnami_magento, I have the provider string configured with
DRIVER=(MySQL ODBC 5.3 ANSI Driver); SERVER=
XX.XXX.XXX.XXX;PORT=3306;DATABASE=bitnami_magento;
USER=me;PASSWORD=mypass;OPTION=3;
Also I have unchecked the "Level zero only" box from Provider Options (MSDASQL) and made sure that ad_hoc queries are allowed. What I am doing wrong?
There are the instructions that I followed
http://dbperf.wordpress.com/2010/07/22/link-mysql-to-ms-sql-server2008/

You have an error in your query:
In the OPENQUERY() you have to use the MySQL table name instead of the MSSQL one (if you want to insert into the MySQL table).
The following syntax should work
INSERT INTO OPENQUERY([MYDB], 'SELECT * FROM mysqlDbName.mysqlTableName') VALUES
('Testi','Testaaja','me#google.com','koe','','','','','','1','N;','','')
Please change the mysqlDbName.mysqlTableName to you MySQL database and table name accordingly.

The problem was I am an idiot. The syntax for Openquery expects a result set to be returned.
So it apparently needs a "dummy query" to be incorporated as a part of the actual query so it will get the result set in response. Writing "where 1=0" makes the query faster as it will not get any actual results in response.
Working example:
insert openquery(MYDB, 'select firstname from admin_user where 1=0') values ('3','Testi','Testaaja','me#google.com','koe12','koe22','','','','0','0','1','','','')
OpenQuery requires a result set to be returned, but UPDATE, DELETE,
and INSERT statements that are used with OpenQuery do not return a
result set.
http://support.microsoft.com/kb/270119/fi

Related

Update column value of one table based on values from another table

If I have two tables...
table_x table_y
| location | latitude | | location | min_latitude | max_latitude |
| -------- | -------- | | -------- | ------------ | ------------ |
| | 41.5 | | point_x | 41.0 | 42.0 |
How do I set table_x.location to table_y.location if table_x.latitude is in between table_y.min_latitude and table_y.max_latitude? I tried the code below but it cannot recognize table_y.
UPDATE table_x
SET table_x.location = table_y.location
WHERE table_x.latitude BETWEEN table_y.min_latitude AND table_y.max_latitude
In your query, table_y comes from nowhere.
Try this:
UPDATE table_x x
JOIN table_y y
ON x.latitude BETWEEN y.min_latitude AND y.max_latitude
SET x.location = y.location
you need to join the second table
But as many rows can be selected for update, you should test this prior of running the query
UPDATE table_x,table_y
SET table_x.location = table_y.location
WHERE table_x.latitude BETWEEN table_y.min_latitude AND table_y.max_latitude

SQL query to find set of doc_ids where there is maximum intersection of ent_ids

I have a table with O(1M) rows with columns doc_id and ent_id where (doc_id, ent_id) is the primary key.
+--------+--------+
| doc_id | ent_id |
+--------+--------+
| 1 | a |
| 1 | b |
| 1 | x |
| 1 | y |
| 2 | a |
| 3 | a |
| 3 | x |
| 3 | y |
| 4 | x |
| 4 | y |
+--------+--------+
My question is, How do I efficiently find a set of doc_ids ( say I need top 1000 or 5000 doc_ids) where there is maximum intersection of ent_ids among that selected set of doc_ids?
For example : In the above table,
say I need top 2 doc_ids where there is maximum intersection among their ent_ids.The result would be - doc_ids = {1,3} with [ common ent_ids={a,x,y}, common ent_ids count=3 ]
say I need top 3 doc_ids where there is maximum intersection among their ent_ids. The result would be - doc_ids = {1,3,4} with [ common ent_ids={x,y}, common ent_ids count=2 ]
footnote - If it's not possible do it efficiently with SQL, any direction towards alternative method of doing it in application code would also be helpful. say, convert to csv -> some data-structure[inverted index?]/library + python code -> result set.

MYSQL - How to merge 2 rows of related data into 1

I am new to mysql and tried to research it but couldn't find any solution. I have a table like this:
| SW_Pair1 | SW_Pair2 | Pair1_VLAN1| Pair1_VLAN2| Pair2_VLAN1| Pair2_VLAN2| Inter | Mgmt| OSPF| Env | Domain|
|-----------------|-----------------|------------|------------|------------|------------|-------|-----|-----|-----|-------|
| Switch1.abc.com | Switch2.abc.com | VLAN-111 | VLAN-333 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch2.abc.com | Switch1.abc.com | VLAN-222 | VLAN-444 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch3.abc.com | Switch4.abc.com | VLAN-121 | VLAN-123 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch4.abc.com | Switch3.abc.com | VLAN-515 | VLAN-717 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch5.abc.com | Switch6.abc.com | VLAN-919 | VLAN-101 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch6.abc.com | Switch5.abc.com | VLAN-105 | VLAN-108 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch7.abc.com | Switch8.abc.com | VLAN-110 | VLAN-115 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
| Switch8.abc.com | Switch7.abc.com | VLAN-199 | VLAN-200 | Unknown | Unknown | 47 | 24 | 0.1 | Dev | abc |
Lets take first 2 rows as an example.
SW_Pair1 in row 1 == SW_Pair2 in row 2
SW_Pair1 in row 2 == SW_Pair2 in row 1
I put them in next row but they can be anywhere in database. Now I would like to merge these 2 so that data in Pair1_VLAN1 and Pair1_VLAN2 in row 2 goes in Pair2_VLAN1 and Pair2_VLAN2 of row 1 and then row 2 disappears. So, here is how the table should look after merge:
| SW_Pair1 | SW_Pair2 | Pair1_VLAN1| Pair1_VLAN2| Pair2_VLAN1| Pair2_VLAN2| Inter | Mgmt| OSPF| Env | Domain|
|-----------------|-----------------|------------|------------|------------|------------|-------|-----|-----|-----|-------|
| Switch1.abc.com | Switch2.abc.com | VLAN-111 | VLAN-333 | VLAN-222 | VLAN-444 | 47 | 24 | 0.1 | Dev | abc |
| Switch3.abc.com | Switch4.abc.com | VLAN-121 | VLAN-123 | VLAN-515 | VLAN-717 | 47 | 24 | 0.1 | Dev | abc |
and so on ..
I am using python 2.7 to push data to sql.
Edit:
I tried below query to add additional checks on DELETE but it failed:
UPDATE yourTable AS a
DELETE FROM yourTable AS b ON a.SW_Pair1 = b.SW_Pair2 AND a.SW_Pair2 = b.SW_Pair1
WHERE Pair2_VLAN1 IS Unknown;
Or better, can it SET the values of Pair1_VLAN1 and Pair1_VLAN2 rows of second switch after it moves it data to switch 1? Maybe over-write the vlan to something like "MERGED". I can then safely remove anything that has "MERGED" in Pair1_VLAN1 and Pair1_VLAN2. I know it will only say that when it's data was successfully got moved to another row.
EDIT2:
nvm .. figured it out. See below:
UPDATE yourTable AS a
JOIN yourTable AS b ON a.SW_Pair1 = b.SW_Pair2 AND a.SW_Pair2 = b.SW_Pair1
SET a.Pair2_VLAN1 = b.Pair1_VLAN1,
a.Pair2_VLAN2 = b.Pair1_VLAN2,
b.Pair1_VLAN1 = "MERGED",
b.Pair1_VLAN2 = "MERGED
WHERE a.SW_Pair1 < a.SW_Pair2;
First update the first row in each pair with the data from the matching row:
UPDATE yourTable AS a
JOIN yourTable AS b ON a.SW_Pair1 = b.SW_Pair2 AND a.SW_Pair2 = b.SW_Pair1
SET a.Pair2_VLAN1 = b.Pair1_VLAN1,
a.Pair2_VLAN2 = b.Pair1_VLAN2
WHERE a.SW_Pair1 < a.SW_Pair2;
The WHERE clause ensures that only one row in each pair (the one with the lower name in SW_Pair1) is updated.
Then delete the rows that weren't updated. They will still have NULL in the columns that were updated by the first query.
DELETE FROM yourTable
WHERE Pair2_VLAN1 IS NULL;
This assumes that there are matching rows for everything. If you need something safer, you'll need to do a join that checks that there's a matching row with the opposite names.
DELETE a FROM yourTable AS a
JOIN yourTable AS b ON a.SW_Pair1 = b.SW_Pair2 AND a.SW_Pair2 = b.SW_Pair1
WHERE a.Pair2_VLAN1 IS NULL
I'm sure there is a cleaner way to do this, but this is a hacky way I came up with.
select
a.sw_pair1,
a.sw_pair2,
a.pair1_vlan1,
a.pair2_vlan1 as pair1_vlan2,
b.pair1_vlan1 as pair2_vlan1,
b.pair2_vlan1 as pair2_vlan2
from TABLENAME a
join TABLENAME b on a.sw_pair1 = b.sw_pair2
where cast(substring_index(substring_index(a.sw_pair1, '.abc.com', 1), 'Switch', -1) as unsigned) % 2 > 0
I'm using the modulo (% 2) to make sure we get the odd numbers in the first column only, therefore having the even numbers in column 2. I'd be curious to see if someone else can come up with a cleaner solution for that than I did. If so, that would help me with some of the things I do from time to time.
This method worked for me and seems simpler than the current answers. This gave your desired output from the sample data.
SELECT
a.SW_Pair1,
a.SW_Pair2,
a.Pair1_VLAN1,
a.Pair1_VLAN2,
b.Pair1_VLAN1 as Pair2_VLAN1,
b.Pair1_VLAN2 as Pair2_VLAN2
FROM test as a , test as b
WHERE a.SW_Pair1 = b.SW_Pair2 AND a.SW_Pair2>b.SW_Pair2;
If you want to store the merged data into table, then #Barmar's solution will work perfectly.
But if you just want to display the data then following query will get the job done:
select least(t1.SW_Pair1,t1.SW_Pair2),greatest(t1.SW_Pair1,t1.SW_Pair2),
t2.Pair1_VLAN1,t2.Pair1_VLAN2,
t1.Pair1_VLAN1 as Pair2_VLAN1,t1.Pair1_VLAN2 as Pair2_VLAN2
from tablet1 as t1
inner join tablet2 as t2
on t2.SW_Pair1 = t1.SW_Pair2 and t2.SW_Pair2=t1.SW_Pair1
group by least(t1.SW_Pair11,t1.SW_Pair2),greatest(t1.SW_Pair1,t1.SW_Pair2);
Hope it helps!

MySQL Substring between two DIFFERENT strings where the second needle comes AFTER the first

I have to extract certain data from a MySQL column. The table looks like so:
+----+---------------------+------------------------+
| id | time | data |
+----+---------------------+------------------------+
| 1 | 2016-10-28 00:12:01 | a Q1!! AF3 !! ext!! z |
| 2 | 2016-10-28 02:19:02 | z !!3F2 !AF66-2!! !!a |
| 3 | 2016-10-28 11:35:03 | AF!a !!! pl6 f !!! dd |
+----+---------------------+------------------------+
I want to grab the string from column data between the characters AF and the NEXT occurrence of !! So ideally the query SELECTid,[something] AS x FROM tbl would result in:
+----+------+
| id | x |
+----+------+
| 1 | 3 |
| 2 | 66-2 |
| 3 | !a |
+----+------+
Thoughts on how to do this? All the other questions I see don't quite relate, as they don't deal with finding the first occurrence of the second needle (!!) AFTER the first needle (AF).
There may be faster ways to do this but this is a good start:
select substring_index(substring_index(data, 'AF', -1), '!!', 1)

Finding the min distance MYSQL

I want to find the min distance between (x2-x1)^2 + (y2-y1)^2 for a particular macId and timeStamp. I'm trying to find a nearest possible gate
location for an individual at one particular instance of time. So, the query should return one unique value of user at one instance of time that is min to the GATE location.
The data set looks like:
X1 Y1 TimeStamp MACID X2 Y2 Gate
| 5618 | 5303 |1 12:22:02 | 54:ea:a8:53:5b:eb | 5844 | 5377 | C24
| 5848 | 5046 |1 12:22:02 | 54:ea:a8:53:5b:eb | 5844 | 5377 | C18
| 6094 | 5464 |1 12:22:02 | 54:ea:a8:53:5b:eb | 5844 | 5377 | C17
| 6021 | 6540 |1 13:09:48 | 48:5a:3f:6a:01:b9 | 6210 | 6801 | C23
| 6366 | 7036 |1 13:09:48 | 48:5a:3f:6a:01:b9 | 6210 | 6801 | C14
| 6366 | 7036 |1 13:09:48 | 48:5a:3f:6a:01:b9 | 6210 | 6801 | C13
The result set should look like below:
X1 Y1 TimeStamp MACID X2 Y2 Gate
| 5848 | 5046 |1 12:22:02 | 54:ea:a8:53:5b:eb | 5844 | 5377 | C18
| 6021 | 6540 |1 13:09:48 | 48:5a:3f:6a:01:b9 | 6210 | 6801 | C23
I have tried this below query but not working:
select min((x2-x1)^2 + (y2-y1)^2), macID, timeStamp from maptable
groupbymacID, timeStamp
I also tried using self joins but seems completely wrong.
May I know where I'm going wrong.
You could use this query:
SELECT m.*
FROM maptable m, (
SELECT TimeStamp, macid, MIN(POW((x2-x1), 2) + POW((y2-y1), 2)) mindist
FROM maptable
GROUP BY TimeStamp, macid
) a
WHERE m.TimeStamp = a.TimeStamp AND m.macid = a.macid
AND POW((x2-x1), 2) + POW((y2-y1), 2) = a.mindist;
SQL Fiddle: http://sqlfiddle.com/#!9/d7979/6
But note that it does not return one row per macid and date, because in your input data the two final rows are the same, so the min distance is the same for gates C13 and C14