Left join fails if not explicitly using ISNULL - sql

I have a large table User and a small table User_purchase in google bigquery.
If I join the two with
SELECT User.id, User_purchase.amount FROM User
LEFT JOIN User_purchase on User.id = User_purchase.user_id,
the query returns error:
Query Failed. Error: Not Implemented: This table cannot be read
But if I join the two with
SELECT User.id, ISNULL(INTEGER(User_purchase.amount), INTEGER(0)) FROM User
LEFT JOIN User_purchase on User.id = User_purchase.user_id,
the query works.
Don't quite understand why the first case does not work.
I assume in the first case I can get all users with their purchase_amount though some users will have NULL as their purchase_amount.
Thanks.

This is a bug relating to nested field names in query replies. I've got a fix for the bug but it won't go out until next week's release. Thanks for bringing it to our attention.

Related

Inner join or something else?

I'm trying to get 2 results into 1 html table, the results of a user being kicked/banned. A UUID is a unique code for every user.
The UUID is stored in BAT_players.
The player name is also stored in BAT_players
There are 3 table's: BAT_players, BAT_ban and BAT_kick
I'm trying to get the history of a user in a html table, this includes kicks and bans. Right now there are only bans in this history, i'm trying to add kicks too. This query is working fine, it shows only bans though.
SELECT BAT_ban.ban_staff, BAT_ban.ban_state, BAT_ban.ban_server, BAT_ban.ban_begin, BAT_ban.ban_end, BAT_ban.ban_id, BAT_kick.kick_id, BAT_ban.ban_reason, BAT_players.BAT_player, ban_soort
FROM BAT_players
INNER JOIN BAT_ban
ON BAT_ban.UUID=BAT_players.UUID
Unfortunately it is not working with this query, it's giving me an empty history. What am i doing wrong with the second inner join?
SELECT BAT_ban.ban_staff, BAT_ban.ban_state, BAT_ban.ban_server, BAT_ban.ban_begin, BAT_ban.ban_end, BAT_ban.ban_id, BAT_kick.kick_id, BAT_ban.ban_reason, BAT_players.BAT_player, ban_soort
FROM BAT_players
INNER JOIN BAT_ban
ON BAT_ban.UUID=BAT_players.UUID
INNER JOIN BAT_kick
ON BAT_kick.UUID=BAT_players.UUID ORDER BY ban_id DESC
;
Thanks!
The problem is that a "null" on any of your inner joins will eliminate that row from the result set.
One solution (perhaps the best solution) is to use left joins.
Another is to take the UNION of two inner joins.
Here's a great link to help visualize INNER, OUTER, LEFT and RIGHT joins:
http://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins
Try using LEFT JOIN:
SELECT BAT_ban.ban_staff, BAT_ban.ban_state, BAT_ban.ban_server, BAT_ban.ban_begin, BAT_ban.ban_end, BAT_ban.ban_id, BAT_kick.kick_id, BAT_ban.ban_reason, BAT_players.BAT_player, ban_soort
FROM BAT_players LEFT JOIN
BAT_ban ON BAT_ban.UUID=BAT_players.UUID LEFT JOIN
BAT_kick ON BAT_kick.UUID=BAT_players.UUID
ORDER BY ban_id DESC
To replace NULL values with empty strings (for SQL Server):
SELECT ISNULL(BAT_ban.ban_staff,''), ISNULL(BAT_ban.ban_state,''), ISNULL(BAT_ban.ban_server,''), ISNULL(BAT_ban.ban_begin,''), ISNULL(BAT_ban.ban_end,''), ISNULL(BAT_ban.ban_id,''), ISNULL(BAT_kick.kick_id,''), ISNULL(BAT_ban.ban_reason,''), BAT_players.BAT_player, ban_soort
FROM BAT_players LEFT JOIN
BAT_ban ON BAT_ban.UUID=BAT_players.UUID LEFT JOIN
BAT_kick ON BAT_kick.UUID=BAT_players.UUID
ORDER BY ban_id DESC
For MySQL, replace ISNULL with IFNULL.
An INNER JOIN requires a value in both tables, so if you use it for both kicks and bans, you will only see users who have been both kicked and banned.
To show users who have been either kicked or banned, you need to change both joins to LEFT JOIN, which essentially means "join if you can, but don't discard rows if you can't". That will include users who have been neither kicked nor banned, so you will also want an extra condition in the WHERE clause saying BAT_ban.ban_id IS NOT NULL OR BAT_kick.kick_id IS NOT NULL.
Note that where a user has multiple bans and multiple kicks, this will produce a row for every combination of ban and kick, since there is no rule to determine which ban should line up with which kick.
An alternative is to write two queries, each using INNER JOIN, and then combine the results. If you give them the same number and type of output columns (leaving NULL for those which aren't applicable) you can use UNION to run both and return the complete result set in one go.

SQL Statement with joins & where clause

I am still working on a Social Networking script, and I have pretty much finished it up now, however there is one problem I have been unable to resolve, that is outputting all of the posts by users AND the user logged in, the latter being the issue.
With the following statement, I have been able to get the status message to output, however other information such as their name and profile information is not.. joined? I think that is what is not happening:
So, when it is not the logged in user, their alongside their status displays, however when its the person logged in (e.g UserID 1, and yes.. I have removed the variable and just put a number) it just shows their message and doesn't access the user information.
SELECT * FROM al_posts
LEFT JOIN al_friendships ON al_posts.user_id = al_friendships.user_b
LEFT JOIN al_users ON al_friendships.user_b = al_users.id
WHERE al_friendships.user_a = '{$_SESSION['UserID']}' OR al_posts.user_id = '{$_SESSION['UserID']}'
The database structure for the tables in question: (note, the friendship table is not an issue so I have left it out)
al_posts table
al_users table
If there is anything anyone notices wrong with the syntax, I would really appreciate it if you could explain what I did wrong so I can correct it. Thanks
Putting the condition on an outer joined table into the where clause turns it effictively into an inner join. You need to apply this in the join condition:
SELECT *
FROM al_posts
LEFT JOIN al_friendships
ON al_posts.user_id = al_friendships.user_b
AND al_friendships.user_a = '{$_SESSION['UserID']}'
LEFT JOIN al_users ON al_friendships.user_b = al_users.id
WHERE al_posts.user_id = '{$_SESSION['UserID']}'
The reason why the condition will make this an inner join is that the rows that "do not" match come back with NULL values in the columns of the outer joined table. Comparing a value against NULL returns "undefined" and thus the condition is false, filtering out all rows that were "outer joined".
I resolved this issue and forgot to mark it as resolved, essentially I got the joins in a real tangle. I sat back, thought about exactly what I wanted to achieve and this was the final working query that I came up with.
SELECT *
FROM al_posts
JOIN al_friendships
ON al_posts.user_id = al_friendships.user_b
AND al_friendships.user_a = '{$_SESSION['UserID']}'
JOIN al_users ON al_friendships.user_b = al_users.id
Thanks for the help guys!

LEFT JOIN SQLite

I'm having problems when making a left join with SQLite.
structure of the tables
contacts: id_c, first_name, last_name, photo_link
messages: id_msg, id_sender, id_recipient, utimestamp, message, chatID
I'm doing a query as follows:
SELECT * FROM messages m
LEFT OUTER JOIN contacts c ON (c.id_c=m.id_sender)
WHERE m.chatID=26
This query returns values ​​from the message table.
But returns null for the contacts table.
I tried several ways and can not resolve this problem. Any suggestions to solve this?
The problem was solved. Probably there was a bug. Once tested in SQL Fiddle, I realized that it worked without problems. Thank you for your attention.
Returning nulls for the columns from the contacts table is exactly what I'd expect from a working LEFT JOIN in the case that there isn't a contact whose id_c matches the id_sender for chatID 26. Have you double-checked that you have such a contact in the contacts table?

Sql syntax to always get one

SELECT dbo.Calls.Description, dbo.TicketRead.IsRead, dbo.TicketRead.UserID
FROM dbo.Calls
LEFT OUTER JOIN dbo.TicketRead ON dbo.Calls.CallID = dbo.TicketRead.TicketID
WHERE dbo.TicketRead.UserID = 1 or is null
I want to get a list of all calls, but also a value indicating if the user have read the call. so I made when a user open's the ticket a new record is added in a special table.
now if no user have read it then it's ok, but if just one user have read this ticket, then the other users don't have this call in the list..
I'm using msSql and .net entity framework.
Are you sure you want to limit the TicketRead table to just UserID # 1?
SELECT c.Description, r.IsRead, r.UserID
FROM dbo.Calls c
LEFT JOIN dbo.TicketRead r
ON c.CallID = r.TicketID
AND r.UserID = 1
This is done joining on multiple conditions... You'll get all of the Calls, but only the IsRead flag from TicketRead when UserID #1 has read it.
I'm not convinced this is actually what you're looking for, and I will be available to update this later if not.
Also please consider using table aliases in the future, I think you'll like it.
you are wanting to do the following:
SELECT dbo.Calls.Description, dbo.TicketRead.IsRead, dbo.TicketRead.UserID
FROM dbo.Calls
LEFT OUTER JOIN dbo.TicketRead ON dbo.Calls.CallID = dbo.TicketRead.TicketID
WHERE
dbo.TicketRead.UserID = 1
or dbo.TicketRead.CallID IS NULL
basically, we are saying here, if there a userid, it has to be 1. otherwise, the records primary key is null (because of the join). Fosco's answer is also right, and much smaller :)

Inner join only returns 7 records

I've got a table with 500.000 records filled with Twitter updates. Then I've got a table with user info.
I basically need all the Twitter records of the people in my user table.
I can do it with this SELECT IN query:
SELECT *
FROM STATUS WHERE twitterUserID
IN (
SELECT twitteruserid
FROM accountLink
)
But that's obviously very slow.
I then tried to do it with a join, but it only shows 7 records. No idea why.
SELECT status . * , accountLink.userId, accountLink.twitterUserId
FROM status
JOIN accountLink
ON status.twitterUserId = accountLink.twitterUserId
Does anyone know what could cause this behaviour and how to solve it?
Try changing it to this:
SELECT status.* , accountLink.userId, accountLink.twitterUserId
FROM status
LEFT JOIN accountLink
ON status.twitterUserId = accountLink.twitterUserId
I suspect that there aren't matches for all the records between status and account link. Doing a left join will select every status regardless of whether or not accountLink has a match.
The JOIN syntax should work, unless the column data types are different.
Per the MySQL Documentation for IN():
The search for the item then is done using a binary search. This means IN is very quick if the IN value list consists entirely of constants. Otherwise, type conversion takes place according to the rules described in Section 11.2, “Type Conversion in Expression Evaluation”, but applied to all the arguments.
Ensuring that your column types match should ensure that the JOIN syntax works correctly.
SELECT s.*, a.twitterUserId, a.userId
FROM status AS s INNER JOIN accountLink AS a
WHERE s.twitterUserId=a.twitterUserId
You DO want to use inner join because you only want to return results IF the "status" table has a record AND a corresponding user record is found in the "accountLink" table. If a "status" table record does NOT have a corresponding user entry, you shouldn't display it (at least according to your post). LEFT OUTER JOIN would display status table records even if there was not a matching entry in the accountLink table.
Here's a great resource for learning about SQL joins:
SQL Joins (w3schools.com)