tags:

views:

80

answers:

5

hello i was looking for a way to combine different mysql queries in a php file so this is my code :

 $sql_query = "SELECT b.*, 
u.username AS MY_Sender
  FROM table_users u, 
       table_blogs b  
 WHERE b.reciever = '0'  
   AND 
   u.user_id = b.sender  

UNION  

SELECT b.*,
u2.username AS MY_Recipient
  FROM table_users u2, 
       table_blogs b  
 WHERE b.reciever != '0'  
  AND 
  u2.user_id = b.reciever  
";

this code works fine unless it cant fetch MY_Recipient

in the above code i need to fetch both sender of blog post and the receiver

is it wrong to use Union to do so ?!

+1  A: 

The field name should be the same

Rename My_sender and My_Recipient to "User" and the union will work.

munissor
The manual only says the columns must have the same type; if they have different names the names form the first result set are used: http://dev.mysql.com/doc/refman/5.1/en/union.html
Artefacto
This works fine, for instance: `select 'a' as col union select 'b' as col2;`
Artefacto
in "general" `UNION` requires the same number and type of columns from each set, not the same column names, while the first set's column names are used for the result set.
KM
A: 

For a union to work, the two select statements should return identical columns. This is where the query is failing.

Kangkan
This is not true - see the [UNION syntax](http://dev.mysql.com/doc/refman/5.1/en/union.html). For example, this works: `SELECT users.id FROM users UNION SELECT users.username FROM users`. It lists all the IDs, followed by all the names. Both `SELECT` statements must return the same number of columns, but the data types and column names do not have to match.
Mike
A: 

You can do this in a single query, but if you want to use unions, the problem is that both queries need to have the same column names:

select b.*, u.username AS username, "sender" as type ...
select b.*, u2.username AS username, "recipient" as type...
Mike Sherov
+3  A: 

I have made a guess at your table structure, and produced something similar. Right or wrong, it might at least help arrive at a suitable solution for you.

Two tables, users and blogs:

CREATE TABLE `users` (
    `id` int(11) NOT NULL auto_increment,
    `username` varchar(255) NOT NULL,
    PRIMARY KEY  (`id`)
) ENGINE=InnoDB;

CREATE TABLE `blogs` (
    `id` int(11) NOT NULL auto_increment,
 `sender` int(11) NOT NULL,
 `receiver` int(11) NOT NULL,
    PRIMARY KEY  (`id`)
) ENGINE=InnoDB;

Add some users:

INSERT INTO `users` (username) VALUES
('Alice'), ('Bob'), ('Carol'), ('Eve');

Add blog entries for some users:

INSERT INTO `blogs` (sender, receiver) VALUES
(1,2), (2,1), (3,4), (4,3), (1,4), (4,1);

For each blog entry, list the sender and receiver:

SELECT
    b.id,
 b.sender AS sender_id,
 b.receiver AS receiver_id,
    us.username AS sender_name,
    ur.username AS receiver_name
FROM blogs AS b
JOIN users AS us ON us.id = b.sender
JOIN users AS ur ON ur.id = b.receiver
ORDER BY b.id;

+----+-----------+-------------+-------------+---------------+
| id | sender_id | receiver_id | sender_name | receiver_name |
+----+-----------+-------------+-------------+---------------+
|  1 |         1 |           2 | Alice       | Bob           |
|  2 |         2 |           1 | Bob         | Alice         |
|  3 |         3 |           4 | Carol       | Eve           |
|  4 |         4 |           3 | Eve         | Carol         |
|  5 |         1 |           4 | Alice       | Eve           |
|  6 |         4 |           1 | Eve         | Alice         |
+----+-----------+-------------+-------------+---------------+

UPDATE 1
table_blogs should probably look like this:

CREATE TABLE IF NOT EXISTS `table_blogs` (
  `bid` int(10) NOT NULL AUTO_INCREMENT,
  `content` varchar(255) DEFAULT NULL,
  `date` varchar(14)  DEFAULT NULL,
  `sender` int(10) NOT NULL,
  `reciever` int(10) NOT NULL,
  CONSTRAINT `fk_sender`
    FOREIGN KEY (`sender` )
    REFERENCES `table_users` (`id` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `fk_receiver`
    FOREIGN KEY (`receiver` )
    REFERENCES `table_users` (`id` )
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  PRIMARY KEY (`bid`)
) ENGINE=MyISAM AUTO_INCREMENT=1 ;

The CONSTRAINT clauses will prevent inserting values for users which don't exist, and will delete entries when users are deleted from the user table.

UPDATE 2
I think this is what you want, but as KM and bobince have stated in the comments, it violates foreign key constraints, which is not really a good idea. So, assuming no foreign key constraints, here's some additional inserts and a modified query:

INSERT INTO `blogs` (sender, receiver) VALUES
(1,0), (0,1), (4,0), (0,4), (2,0), (0,2);

SELECT
    b.id,
 b.sender AS sender_id,
 b.receiver AS receiver_id,
    IFNULL(us.username, ur.username) AS sender_name,
    IFNULL(ur.username, us.username) AS receiver_name
FROM blogs AS b
LEFT JOIN users AS us ON us.id = b.sender
LEFT JOIN users AS ur ON ur.id = b.receiver
ORDER BY b.id;

+----+-----------+-------------+-------------+---------------+
| id | sender_id | receiver_id | sender_name | receiver_name |
+----+-----------+-------------+-------------+---------------+
|  1 |         1 |           2 | Alice       | Bob           |
|  2 |         2 |           1 | Bob         | Alice         |
|  3 |         3 |           4 | Carol       | Eve           |
|  4 |         4 |           3 | Eve         | Carol         |
|  5 |         1 |           4 | Alice       | Eve           |
|  6 |         4 |           1 | Eve         | Alice         |
|  7 |         1 |           0 | Alice       | Alice         |
|  8 |         0 |           1 | Alice       | Alice         |
|  9 |         4 |           0 | Eve         | Eve           |
| 10 |         0 |           4 | Eve         | Eve           |
| 11 |         2 |           0 | Bob         | Bob           |
| 12 |         0 |           2 | Bob         | Bob           |
+----+-----------+-------------+-------------+---------------+
Mike
that was nice answer but you didnt mentioned , what if the reciver is 0 !?! when the reciver is 0 it means the sender posting it in his own page and else if reciver has a value , then he is posting it in other's page
Mac Taylor
`table_blogs` looks okay, but you haven't posted the user table. `table_blogs` would benefit from a couple of [foreign key constraints](http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html) to prevent invalid values being inserted. I don't think that there is a need for the index on `bid` either, as the primary key is already indexing it.
Mike
table_users is simple just a user_id and username field is necessary , so plz read my previous comment , the condition should be what if the receiver is 0 , then the sender is posting in its own page and the receiver should be the sender
Mac Taylor
@Mac Taylor, your zero `0` value logic is crazy and makes foreign keys impossible. I'd get rid of that and create a `Blog` table that has one row per blog, including the blog owner. and then a BlogEntry table that is similar to what you have posted, but with a FK to the Blog table, you can tell the owner by joining BlogEntry to the Blog.
KM
@Mac Taylor: You edited your comment after I replied to it! :-) I'll have another look.
Mike
Yeah, don't use `0` for an out-of-band value on a reference to another table, that'll bite you bad when you move to another table/database type that has foreign key support. You really should be using InnoDB and foreign keys; there's little good reason to run MyISAM today, other than FULLTEXT. As well as the separate join table, you could also use a `NULL` to mean no-foreign-reference, or in this case surely if it is someone posting to their own page, `receiver=sender` would be appropriate?
bobince
@Mac Taylor: I've updated the post to provide a solution, but please take note of the comments by KM and bobince. This works, but lack of foreign key constraints may come back to haunt you.
Mike
yeah that works fine , but anyway i didn't pay attention to foreign key usage and here we are , that we cant change that strategymaybe i should read more about these things . plz clean your answer just the update2 is enough
Mac Taylor
I don't quite understand the sender/receiver idea for a blog, but if we forget that for a moment, foreign key constraints could be implemented if you simply insert the same value in the sender and receiver columns if both sender and receiver are the same user. But as I'm not really all that clear on what you are doing, I'm not really sure if that is appropriate or not.
Mike
A: 

What are you trying to do? You say there are two queries there, but it looks like the same query to me, just one of them having a different table alias.

The only purpose I can see for the UNION is to put all the rows with a zero-receiver before those without. But you can do that more simply by using a computed ORDER BY:

SELECT b.*, u.username
FROM table_blogs AS b
JOIN table_users AS u ON u.user_id=b.sender
ORDER BY b.receiver<>0
  • if there are no negative receiver IDs, you could change that to ORDER BY b.receiver as 0 would always come first, which would then be possible to index if you needed to;

  • ANSI JOIN is generally considered more readable than the old-school method of implicit joins in the WHERE conditions;

  • <> is preferable to !=, which is a non-standard MySQL synonym;

  • check the spelling of receiver.

bobince