SQL (MYSQL, Postgres) Lookup/report table - mysql

I'm basically making a lookup table for my three tables but its not doing what I want. Those 3 tables were created by loading 3 different csv files.
What I'm trying to do is inserting the ID's from those tables into the lookup one.
This is what I keep getting:
---------------Lookuptable---------------
|lookup_ID|Table1_ID|Table2_ID|Table3_ID|
| 1 | 1 | | |
| 2 | 2 | | |
| 3 | 3 | | |
| | | 1 | |
| | | 2 | |
| | | 3 | |
| | | | 1 |
| | | | 2 |
| | | | 3 |
What I need is:
---------------Lookuptable---------------
|lookup_ID|Table1_ID|Table2_ID|Table3_ID |
| 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 2 |
| 3 | 3 | 3 | 3 |
I kind of get why this is happening, it inserts one row bellow every time with single inserts like
insert into Lookuptable(Table1_ID) select T1id from Table1;
and the others...
But I've tried nested ones too like
insert into Lookuptable(Table1_ID, Table2_ID, Table3_ID)
select Table1.T1id, Table2.T2id, Table2.T2id from Table1, Table2, Table3;
but still doesn't work. In fact this one just crashes the Mysql server and has an endless query on Postgres. I've tried other nested examples but none worked.
I'm also using Foreign Keys which work when I manually input a new value, but since the other tables come from loaded CSV files I have to input the values already there manually.
I'm really not sure what to do.

If I understand correctly what you want something like this should work
https://www.db-fiddle.com/f/k6CGsVXazSqJDfwKkdr6S7/1
SET #i:=0,#j:=0,#h:=0;
INSERT INTO Lookuptable
SELECT NULL,t1.ID,t2.ID,t3.ID FROM
( SELECT #i:=(#i+1) AS temp_id,ID FROM Table1 ) t1
INNER JOIN
( SELECT #j:=(#j+1) AS temp_id ,ID FROM Table2 ) t2 ON t1.temp_id=t2.temp_id
INNER JOIN
( SELECT #h:=(#h+1) AS temp_id ,ID FROM Table3 ) t3 ON t2.temp_id=t3.temp_id;

Related

Mysql lookup table (Mysql performance issue)

I've made a look up table for all my tables. What I'm trying to do is what it is supposed to do, correspond the ID's to the matched values.
I use mysql work bench, server 5.7(newest version doesn't work for me).
I have thousands of values and 6 tables. For a simple explanation lets say I have 3 tables.
------------------table1------------------
| t1ID | Person | Purchase| Code |
| 1 | Jon | 50 | 111 | /* Code = t3ID */
| 2 | Dan | 100 | 222 | /* Purchase = Buyer in table2 */
| 3 | Pete | 200 | 333 |
(Many more)
------------------table2------------------
| t2ID | Buyer | Date | Barcode |
| 1 | 200 | 1/1/20 | ABC111 | /* Buyer = Purchase in table1 */
| 2 | 100 | 2/1/20 | ABC222 | /* Barcode = Item_ID in table3 */
| 3 | 50 | 3/1/20 | ABC333 |
(Many more)
------------------table3---------
| t3ID | Item | Item_ID | /* t3ID = Code*/
| 111 | Laser | ABC111 | /* Item_ID = Barcode */
| 222 | Phones | ABC222 |
| 333 | Tables | ABC333 |
(Many more)
I get this... I need this...
-------------Lookup_Table------------- -------------Lookup_Table----------
| lookID | t1ID | t2ID | t3ID | | lookID | t1ID | t2ID | t3ID |
| 1 | 1 | 1 | 111 | | 1 | 1 | 3 | 333 |
| 2 | 2 | 2 | 222 | | 2 | 2 | 2 | 222 |
| 3 | 3 | 3 | 333 | | 3 | 3 | 1 | 111 |
This table is connected by foreign keys and these values were added manually here because the original tables came from CSV files.
My problem is performance or maybe I'm doing it wrong on mysql. When I query by the table ID its works perfectly fine but the values will not match since I added the tableID's afterwards, there are repeated values in certain fields and all the values on the tables are random and they are only connected by those specific values shown above.
When I query select or any other one like "on table1.Purchase = table2.Buyer" or "where", to make the comparison and add them to the table properly, the localhost server crashes. It loses connection to mysql server. Also, if its directly compared between the tables, it works but takes over 5 minutes to do that comparison.
If I limit the rows between 0-10000 is fine, above that or if I don't limit it just crashes. I can't limit since I have over 20000 rows, for now.
example is
update Lookup_Table lk inner join table1 t1 on t1.t1ID = lk.t1ID
inner join table2 t2 on t2.Buyer = t1.Purchase
set lk.t2ID = t2.t2ID;
Same thing between the other tables. Any idea if I'm doing it wrong or if there's another way of doing this? I've tried so many different things and no luck.

MySQL How can I make a better query to connect two tables through my bridge table?

I have these tables:
words:
+----+------+
| ID | DATA |
+----+------+
| 1 | jo |
| 2 | yes |
| 3 | jupp |
| 4 | yeah |
| 5 | jepp |
| 6 | joah |
| 7 | ne |
| 8 | nee |
| 9 | no |
| 10 | nope |
| 11 | nah |
+----+------+
statements:
+----+------+
| ID | DATA |
+----+------+
| 1 | ja |
| 2 | nein |
+----+------+
and a bridge table that connects the words from table "words" with the DATA from table "statements":
bridge:
+--------------+---------+
| ID_statement | ID_word |
+--------------+---------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 1 | 6 |
| 2 | 8 |
| 2 | 9 |
+--------------+---------+
I wanted to get a SELECT QUERY to get all words associated with the statement "ja".
this query does the job, but seems more complicated than it should be:
SELECT words.DATA FROM words
JOIN bridge ON words.ID = bridge.ID_word
JOIN statements ON statements.ID = bridge.ID_statement
WHERE statements.ID = (
SELECT ID FROM statements WHERE statements.DATA = "ja"
);
Intuition tells me that I am doing that far to comlicated, but I can't figure out where the complication lies.
awkward.
I like to name the primary keys the same as the columns that reference them. So in your example, in the words table, you'd name the primary key ID_word. In the statements table, you'd name the primary key ID_statement.
The advantage is that you can make your SQL join a little more concise with the USING(...) syntax. This syntax assumes there's a column by that name in both tables of a join, and you want the join to match where the column is equal to the same column in the other table.
SELECT words.DATA FROM words
JOIN bridge USING (ID_word)
JOIN statements USING (ID_statement)
WHERE statements.DATA = 'ja';
Also you don't need to run a subquery in your example. The rows in statement matching the IDs from the rows in statement where DATA='ja' are the same set as the rows in statement where DATA='ja'.
how would one describe the relationship here? one-to-many?
The relationship modeled by a bridge table is a many-to-many relationship. The specific data in your example doesn't show it, but it's possible that many different statements could reference the same word. What you do show is that each statement can reference many words.

MYSQL | select inverse value between 2 tables

I would like to SELECT the records from a table that have different values from another one.
Table 1.
+--------+-------+
| userID | tagID |
+--------+-------+
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
+--------+-------+
Table 2.
+---------+-------+
| ChaName | tagID |
+---------+-------+
| Hello | 1 |
| How | 2 |
| Are | 3 |
| You | 4 |
| Today | 5 |
| Guys | 6 |
| ? | 7 |
+---------+-------+
And then it suppose to be
+--------+-------+---------+
| userID | tagID | chaNAME |
+--------+-------+---------+
| 1 | 1 | Hello |
| 1 | 5 | Today |
| 1 | 6 | Guys |
| 1 | 7 | ? |
+--------+-------+---------+
It looks very simple but I can't find the way to solve it.
Thank you for all of your answers <3
PS. btw i've tried to use ' not in ' but it got an error
Unrecognized keyword. (near "not in" at position 92)
To get the output, you need to use an outer join. A left join will give you all the records from left table table2 and only matching records from right table table1. That means you will get null for records in table1 which doesn't exist in table2. You can use this property in where clause to get only your expected records.
Also you cannot decide on userid on records in table2. If you want to hardcode them as 1, then use select 1 as userid, ... in select clause.
SQLFiddle Demo
select t2.tagid,t2.chaname
from
table2 t2 left join table1 t1
on t1.tagid=t2.tagid
where t1.tagid is null
select a.userid,
b.tagid,
b.chaname
from table1 a,table2 b
where b.tagid not in (select tagid from tabel1)

mysql select with group by returning rows with a preference order

I have the following mysql query result:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | ola1 | 1 |
| 1 | hello1 | 2 |
| 1 | bonjour1 | 3 |
| 2 | ola2 | 1 |
| 2 | bonjour2 | 3 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
What I want is a group_by query by id and that gives me for each id the title with a order of preference for lang field. Example:
Result for lang preference order 1, 2, 3:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | ola1 | 1 |
| 2 | ola2 | 1 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
Result for lang preference order 3, 2, 1:
+----+------------+-------------+
| id | title | lang |
+----+------------+--------------
| 1 | bonjour1 | 3 |
| 2 | bonjour2 | 3 |
| 3 | hello3 | 2 |
| 4 | bonjour4 | 3 |
+----+------------+-------------+
Thanks!
It is either not possible, or, not with in my SQL skills to execute that in one query. I always end up using a temporary template and two SQL commands for these problems:
(assuming that your table is called Table1 and the temporary table should be called tempTable)
SELECT Table1.id, Min(Table1.lang) AS Min_Of_lang INTO tempTable FROM Table1 GROUP BY Table1.id ORDER BY Table1.id;
SELECT Table1.* FROM tempTable INNER JOIN Table1 ON (tempTable.MinOflang = Table1.lang) AND (tempTable.id = Table1.id);
The first command creates a new table (that overrides the current table if it exists). The second command uses the first table to produce the desired result set.
To change from your first desired results table to the second, use Max instead of min in the first query.
Somebody else may well have a more elegant solution than mine. Also, an extra SQL statement could be added to delete the temporary table.
This is a feature that is not defined in MySQL. The displayed value in a non-aggregated column is undetermined. read more here (MySQL Documentation).
(Standard SQL doesn't allow to include non-aggregated columns when using GROUP BY, I guess this is one of the reasons).
From your description of the what you want to do, you should simple SELECT all rows with the lang you are looking for
SELECT * FROM your_table WHERE lang = 1

Fast SQL search and sort without temporary tables

I have two tables.
Tab1:
+------------+
| id | title |
+------------+
| 1 | B |
| 2 | C |
| 3 | A |
| 4 | A |
| 5 | A |
| 6 | A |
| ... |
+------------+
PK: ID
Index: title
Tab2:
+-------------------------------------------+
| id | item_id | item_key | item_value |
+-------------------------------------------+
| 1 | 1 | value | $4 |
| 2 | 1 | url | http://h.com/ |
| 3 | 2 | value | $5 |
| 4 | 3 | url | http://i.com/ |
| 5 | 3 | value | $1 |
| 6 | 3 | url | http://y.com/ |
| 7 | 4 | value | $2 |
| 8 | 4 | url | http://z.com/ |
| 9 | 5 | value | $1 |
| 10 | 5 | url | http://123.com/ |
| ... |
+-------------------------------------------+
PK: id
Index: item_id, item_key
item_id is a foreign key from tab1.
How do I make it so I get a table of ids from Tab1 in order according to criteria from both tables. The criteria are the following:
Order ASC by title. If title is the same,
Order DESC by value. If both title and value is the same,
Prioritize items who's 'url' key contains '123.com'.
The resulting table with the ordered results would be:
+------------+
| id | title |
+------------+
| 4 | A |
| 5 | A |
| 3 | A |
| 6 | A |
| 1 | B |
| 2 | C |
| ... |
+------------+
I know I can do it with:
SELECT Tab1.id, Tab1.title
FROM Tab1
JOIN Tab2 t2_val ON t2_val.item_id = Tab1.id AND t2_val.item_key='value'
JOIN Tab2 t2_url ON t2_url.item_id = Tab1.id AND t2_url.item_key='url'
ORDER BY title,
t2_val.item_value DESC,
t2_url.item_value LIKE '%123.com%' DESC
but for large data sets, it's too slow. Is there a way to do it faster? I've set index on id and title in Tab 1, and on item key in Tab 2. Now I'd like to drop temporary tables if I could, so that means no joins, right?
How else could this be done?
First, for larger data sets, your result set is going to be larger. What are you doing with the data afterwards? The decrease in performance could be primarily related to the data coming out of the database and not to the processing in the database.
Next, what indexes do you have? The query seems to be begging for an index on tab2(item_key, item_id) to resolve the joins.
And, finally, I don't see how you can get around the final sorting for order by, because it is using values from both tables.
You are using an "entity-attribute-value" (EAV) model. This can be inherently slow when choosing lots of columns for lots of records. If you know that you have these two fields, think about changing the data model so url and value are columns in tab1.
Try this:
SELECT t1.id, t1.title
FROM Tab1 t1
INNER JOIN (SELECT item_id, MAX(item_key='value', item_value, '') AS 'value',
MAX(item_key='url', item_value, '') AS 'url'
FROM Tab2 GROUP BY item_id
) t2 ON t2.item_id = t1.id
ORDER BY t1.title, t2.value DESC, IF(t2.url LIKE '%123.com%', 0, 1);