Selecting entire rows from two tables - mysql

I don't know if it's possible and i might be asking a stupid question here, if so, forgive me.
I have two tables that are somewhat similar but not entirely.
Table 1 (user_opinions)
| o_id | user_id | opinion |is_shared_from| date,isglobal etc
|:---------|---------|:------------:|:------------:|
| 1 | 11| text 1 | 0
| 2 | 13| text 2 | 2
| 3 | 9| text 3 | 0
Table 2 (Buss_opinions)
| bo_id | o_id | user_id | opinion | date
|:---------|--------|:------------:|:------------:|
| 1 | 2| 52 | bus text 1
| 2 | 3| 41 | bus text 2
If i do a standard select and join like this:
SELECT * FROM user_opinions uo
JOIN Buss_opinions bo
ON uo.o_id = bo.o_id
This will return rows with both table's data joined together.
My question is, what if i wanted to get data from these two tables in seperate rows.
Result should be something like this:
| oid | bo_id | opinion | nb: and other rows from both tables
|:---------|---------|:------------:|
| 1 | NULL | text 1 | nb:from table 1
| NULL | 1| bus text 1| nb:from table 2
| 2 | NULL | text 2 |nb:from table 1
and so on
It gets both table's data and where there's no common field it puts a NULL value in the field. Is there a type of join for this? or are there other ways of doing this?

One way you could go about it is using a UNION (http://dev.mysql.com/doc/refman/5.0/en/union.html):
SELECT oid AS OID, null AS BOID, user_id AS USERID, opinion AS Opinion
FROM table1
UNION
SELECT null AS OID, bo_id AS BOID, user_id AS USERID, opinion AS Opinion
FROM table2
Edit: You could even take this a step further and marry it with the CONCAT function:
SELECT CONCAT('OID-', oid) AS ID, user_id AS USERID, opinion AS Opinion
FROM table1
UNION
SELECT CONCAT('BOID-', bo_id) AS ID, user_id AS USERID, opinion AS Opinion
FROM table2

Related

How to fetch data ( without duplicates records ) from two different tables ? where both tables have common value

Table 1
newpancard
id | name | cardno | status |
-----------------------------
1 | name1| 909099 | done |
2 | name2| 800099 | done |
3 | name3| 965099 | pending|
Table 2
oldpancard
id | name | cardno | status |
-----------------------------
1 | name4| 111119 | done |
2 | name5| 323239 | done |
3 | name6| 734349 | pending|
4 | name7| 609099 | done |
can we get fetch data from both tables where status = done in both tables?
I am trying the following query but getting duplicates data in bulk.
SELECT tb1.*, tb2.*
FROM `newpancard` tb1
JOIN `oldpancard` tb2
ON tb1.status = tb2.status
please correct me. Thanks
I think you actually want a UNION:
SELECT * FROM newpancard WHERE status='done'
UNION
SELECT * FROM oldpancard WHERE status='done'
We use a UNION (rather than UNION ALL) so we don't get duplicate records from newpancard and oldpancard
Output (from your sample data):
id name cardno status
1 name1 909099 done
2 name2 800099 done
1 name4 111119 done
2 name5 323239 done
4 name7 609099 done
SQLFiddle

Advance searching in MySQL according to synonym words

I have three tables, which are below with related details
1. Primary words
+----+---------+
| id | word |
+----+---------+
| 1 | Machine |
+----+---------+
| 2 | phone |
+----+---------+
2. Alternative words
+----+------------+-----------+
| id | primary_id | word |
+----+------------+-----------+
| 1 | 1 | system |
+----+------------+-----------+
| 2 | 1 | feature |
+----+------------+-----------+
| 3 | 2 | telephone |
+----+------------+-----------+
3. product table
+----+------------------+
| id | name |
+----+------------------+
| 1 | mobile system |
+----+------------------+
| 2 | computer machine |
+----+------------------+
| 3 | wired telephone |
+----+------------------+
Now twist is that whenever user search with "machine" in product table then display results of product with table name have "machine" or "system" or "feature" and if search with "system" or "feature" then also display results of "machine" or "system" or "feature".or vice vera.
Would you please suggest me how can solve this one?
If I understand correctly what you are asking...
SQL
SELECT *
FROM Product P
WHERE EXISTS(SELECT fw.Word --(6) select all products that exist in this query
FROM (SELECT pw.Word --(1) select all Primary words matching input
FROM PrimaryWords pw
WHERE pw.Word = 'machine'
UNION --(3) union the results from both selects
SELECT aw.Word --(2) select all Alternative words that match input or have its primary matching it
FROM PrimaryWords pw INNER JOIN AlternativeWords aw
ON pw.Id = aw.PrimaryId
WHERE pw.Word = 'machine'
OR aw.Word = 'machine') as fw --(4) alias the result
WHERE p.Name LIKE '%' || fw.Word || '%'); -- (5) filter products that match the valid words
you can read the comments ordered by the numbering in ().
First of all you need to take those two table data inti one and then give condition.
Select word from(
SELECT id,word FROM PrimaryWords
Union all
Select primaryid,word from AlternativeWords a
) where id in ( select id from primarywords where word='yoursearchketword'
Union
Select primaryid from AlternativeWords where word='yoursearchketword')
Updated Answer as per your product table.
Now you need to cross join the product table, because there is no relationship between them.
One more thing is you have to use like operator here to compare you desired result with prouct table's name column. Here I have given small idea How to accomplish that, but you can easily improve the same.
Select a.word,b.name from
(Select word from(
SELECT id,word FROM PrimaryWords
Union all
Select primaryid,word from AlternativeWords a
) where id in ( select id from primarywords where word='yoursearchketword'
Union
Select primaryid from AlternativeWords where word='yoursearchketword')) a, product b
Where a.word LIKE CONCAT('%',name, '%');
I suggest to put it in one table like this:
id | primary_id | word
1 | 1 | machine
2 | 2 | phone
3 | 1 | system
4 | 1 | feature
5 | 2 | telephone
And the query will be like this, lets take machine word as an example:
Select word from MyTable where primary_id in
(select primary_id from MyTable where word = "machine")
The output: machine, system, feature
Update
In case you have more columns, for example to show how much related are these words, you can add one more table to map between words, like the following:
id | w1_id | w2_id | relation
1 | 1 | 3 | 80
2 | 2 | 5 | 90
3 | 1 | 4 | 60
4 | 3 | 4 | 60
And the words table will list only the words like:
id| word
1 | machine
2 | phone
3 | system
4 | feature
5 | telephone
In this thread you will find a long discussion talking about way you have to design the layout of your schema as well as hints in how retrieve your data.

Mysql needs to duplicate records using select query

I have a post table like following,
| ID | TITLE | NUMBER_OF_REPEAT
| 1 | post1 | 2
| 2 | post2 | 1
| 3 | post3 | 3
From the above table I need a select query to produce the row depending upon NUMBER_OF_REPEAT field.
Expected output,
| ID | TITLE
| 1 | post1
| 1 | post1
| 2 | post2
| 3 | post3
| 3 | post3
| 3 | post3
This kind of duplication should support the pagination also. Please help me.
Thanks in advance.
Something like this
SQL Fiddle
create table numbers (number int);
insert into numbers
select 1
union
select 2
union
select 3;
SELECT id, title
FROM tabl
JOIN Numbers
ON tabl.repeater >= Numbers.number
order by id
Its messy,but modify the numbers table for more repeats.
SQL Fiddle
I don't think this should do by DBMS. this can do in programe.
But you can create another table with only two rows and join with post table
let's say table dup with two rows.
SELECT ID ,TITLEfrom post, dup

How to get count of matching strings in a large table

I have a table with following structure:
+-----+-------------------+
| ID | Name |
+-----+-------------------+
| 1 | abc |
+-----+-------------------+
| 2 | abc (duplicate) |
+-----+-------------------+
| 3 | bcd |
+-----+-------------------+
| 4 | bcd (duplicate) |
+-----+-------------------+
| 5 | bcd (duplicate) |
+-----+-------------------+
| 6 | efg |
+-----+-------------------+
| 7 | hij |
+-----+-------------------+
I need to count each Name occurance (with (duplicate) included), i.e.:
+-------------------+--------+
| Name | Count |
+-------------------+--------+
| abc | 2 |
+-------------------+--------+
| bcd | 3 |
+-------------------+--------+
| efg | 1 |
+-------------------+--------+
| hij | 1 |
+-------------------+--------+
I want to mention, that Name column is actually have type TINYTEXT. And there will be very lot of rows in it: 5396 in test mode already. I tried to make self join of table by TRIM(REPLACE(Name, '(duplicate)', '')) with grouping:
SELECT
DISTINCT TRIM(REPLACE(`t`.`Name`, '(duplicate)', '')) as `name`,
COUNT(`s`.`ID`) as `count`
FROM
`Table` as `t` INNER JOIN `Table` as `s` ON
TRIM(REPLACE(`t`.`Name`, '(duplicate)', '')) LIKE TRIM(REPLACE(`s`.`Name`, '(duplicate)', ''))
GROUP BY 1;
And... Well, it took 122.62 sec (?!) with result of 4846 rows on my development machine.
Q1: Was it a correct approach?
Q2: Is there any way to make it faster?
Any help would be appreciated.
Just remove the "duplicate" text:
select replace(name, ' (duplicate)', ''), count(*)
from mytable
group by 1
This should be quicker, although with that many rows you're basically storing a growing array of objects that you're counting and since it's a TINYTEXT field it can be immense.
select Name,count(ID) from Table group by Name
I see what you're saying now. Here's an updated SQL:
select DISTINCT TRIM(REPLACE(Name, ' (duplicate)', ''))
as name, count(ID) from Table group by name

Select rows from one table, join most recent row from other table with one-to-many relationship

What I would like to do is select a specific set of rows from one table (table A) and join with another table (table B), such that only one record will appear from table A, joined with the most recent record from table B, based on a datetime column.
For example, table A has this structure (heavily simplified):
id | col_1 | col_2
---+-----------+----------------
1 | something | something else
2 | val_1 | val_2
3 | stuff | ting
4 | goats | sheep
And table B looks like this:
id | fk_A | datetime_col | col_3
---+-----------+---------------------+--------
1 | 1 | 2012-02-01 15:42:14 | Note 1
2 | 1 | 2012-02-02 09:46:54 | Note 2
3 | 1 | 2011-11-14 11:18:32 | Note 3
4 | 2 | 2009-04-30 16:49:01 | Note 4
5 | 4 | 2013-06-21 15:42:14 | Note 5
6 | 4 | 2011-02-01 18:44:24 | Note 6
What I would like is a result set that looks like this:
id | col_1 | col_2 | datetime_col | col_3
---+-----------+----------------+---------------------+--------
1 | something | something else | 2012-02-02 09:46:54 | Note 2
2 | val_1 | val_2 | 2009-04-30 16:49:01 | Note 4
3 | stuff | ting | NULL | NULL
4 | goats | sheep | 2013-06-21 15:42:14 | Note 5
So you can see that table B has been joined with table A on B.fk_A = A.id, but only the most recent corresponding record from B has been included in the results.
I have tried various combinations of SELECT DISTINCT, LEFT JOIN and sub-queries and I just can't get it to work, I either get no results or something like this:
id | col_1 | col_2 | datetime_col | col_3
---+-----------+----------------+---------------------+--------
1 | something | something else | 2012-02-01 15:42:14 | Note 1
1 | something | something else | 2012-02-02 09:46:54 | Note 2
1 | something | something else | 2011-11-14 11:18:32 | Note 3
2 | val_1 | val_2 | 2009-04-30 16:49:01 | Note 4
3 | stuff | ting | NULL | NULL
4 | goats | sheep | 2013-06-21 15:42:14 | Note 5
4 | goats | sheep | 2011-02-01 18:44:24 | Note 6
...with the records from table A repeated.
Obviously my SQL-fu is just not good enough for this task, so I would be most grateful if one of you kind people could point me in the right direction. I have done quite a bit of Googling and searching around SO and I have not found anything that matches this specific task, although I am sure the question has been asked before - I suspect there is an SQL keyword that I am forgetting/unaware of and if I searched for that I would find the answer instantly.
I think this question deals with the same problem although I am not 100% sure and the accepted answer involves SELECT TOP, which I thought (?) was not valid in MySQL.
As my actual query is much more complicated and joins several tables, I shall show it in case it makes any difference to how this is done:
SELECT `l` . * , `u`.`name` AS 'owner_name', `s`.`name` AS 'acquired_by_name', `d`.`type` AS `dtype` , `p`.`type` AS `ptype`
FROM `leads` l
LEFT JOIN `web_users` u ON `u`.`id` = `l`.`owner`
LEFT JOIN `web_users` s ON `s`.`id` = `l`.`acquired_by`
LEFT JOIN `deal_types` d ON `d`.`id` = `l`.`deal_type`
LEFT JOIN `property_types` p ON `p`.`id` = `l`.`property_type`
This query works and returns the data I want (sometimes I also add a WHERE clause but this works fine), but I would now like to:
LEFT JOIN `notes` n ON `n`.`lead_id` = `l`.`id`
...where notes contains the "many records" and leads contains the "one record" they relate to.
It should also be noted that potentially I would also want to return the oldest record (in a different query) but I imagine this will be a simple case of inverting an ASC/DESC somewhere, or something similarly easy.
I think this will help you:
SELECT A.id, A.col_1, A.col_2, A.datetime_col, A.col_3
FROM
(SELECT B.id, B.col_1, B.col_2, C.datetime_col, C.col_3
FROM tableA B LEFT OUTER JOIN tableB C ON B.id = C.id
ORDER BY C.datetime_col desc) as A
GROUP BY A.id