2014-11-21 27 views
8

In PostgreSQL 9 su CentOS 6 ci sono 60000 i record nella pref_users tabella:Join esterno sinistro: come restituire un booleano per l'esistenza nella seconda tabella?

# \d pref_users 
        Table "public.pref_users" 
    Column |   Type    |  Modifiers  
------------+-----------------------------+-------------------- 
id   | character varying(32)  | not null 
first_name | character varying(64)  | not null 
last_name | character varying(64)  | 
login  | timestamp without time zone | default now() 
last_ip | inet      | 
(... more columns skipped...) 

e un altro tavolo detiene circa 500 ID di utenti che non sono autorizzati a giocare più:

# \d pref_ban2 
       Table "public.pref_ban2" 
    Column |   Type    | Modifiers 
------------+-----------------------------+--------------- 
id   | character varying(32)  | not null 
first_name | character varying(64)  | 
last_name | character varying(64)  | 
city  | character varying(64)  | 
last_ip | inet      | 
reason  | character varying(128)  | 
created | timestamp without time zone | default now() 
Indexes: 
    "pref_ban2_pkey" PRIMARY KEY, btree (id) 

In un PHP script Sto tentando di visualizzare tutti i 60000 utenti da pref_users in un jQuery-DataTable. E vorrei contrassegnare gli utenti vietati (gli utenti trovati in pref_ban2).

Ciò significa che ho bisogno di una colonna denominata ban per ogni record nella mia query contenente true o false.

Così sto cercando un esterno sinistro join query:

# select       
     b.id, -- how to make this column a boolean? 
     u.id, 
     u.first_name, 
     u.last_name, 
     u.city, 
     u.last_ip, 
     to_char(u.login, 'DD.MM.YYYY') as day 
from pref_users u left outer join pref_ban2 b on u.id=b.id 
limit 10; 
id | id | first_name | last_name | city  |  last_ip  | day  
----+----------+-------------+-----------+-------------+-----------------+------------ 
    | DE1  | Alex  |   | Bochum  | 2.206.0.224  | 21.11.2014 
    | DE100032 | Княжна Мэри |   | London  | 151.50.61.131 | 01.02.2014 
    | DE10011 | Aлександр Ш |   | Симферополь | 37.57.108.13 | 01.01.2014 
    | DE10016 | Semen10  |   | usa   | 69.123.171.15 | 25.06.2014 
    | DE10018 | Горловка |   | Горловка | 178.216.97.214 | 25.09.2011 
    | DE10019 | -Дмитрий- |   | пермь  | 5.140.81.95  | 21.11.2014 
    | DE10047 | Василий  |   | Cумы  | 95.132.42.185 | 25.07.2014 
    | DE10054 | Maedhros |   | Чикаго  | 207.246.176.110 | 26.06.2014 
    | DE10062 | ssergw  |   | москва  | 46.188.125.206 | 12.09.2014 
    | DE10086 | Вадим  |   | Тула  | 109.111.26.176 | 26.02.2012 
(10 rows) 

Come si può vedere la colonna b.id sopra è vuoto - perché questi 10 gli utenti non sono vietati.

Come ottenere un valore false in quella colonna anziché in una stringa?

E non lo sono dopo l'espressione coalesce o case, ma sto cercando il modo "corretto" per eseguire una tale query.

risposta

8

Un'istruzione CASE o COALESCE con un join esterno è il modo corretto per farlo.

select 
    CASE 
    WHEN b.id IS NULL THEN true 
    ELSE false 
    END AS banned,       
    u.id, 
    u.first_name, 
    u.last_name, 
    u.city, 
    u.last_ip, 
    to_char(u.login, 'DD.MM.YYYY') as day 
from pref_users u 
left outer join pref_ban2 b 
    on u.id=b.id 
limit 10; 
+0

Grazie per la risposta, ma non dovrei usare (più efficace) "esiste" qui? –

+0

Quindi 'EXISTS' funge da filtro. Se usi 'ESISTE', non otterrai il record se è filtrato. Se vuoi visualizzare un valore 'boolean', starai meglio con un' CASE'. –

+0

A questo punto, è possibile utilizzare "EXISTS" anziché "OUTER JOIN", ma ciò non cambierà la logica booleana. –

3

"IS NULL" e "non è nullo" restituiscono un valore booleano, quindi questo dovrebbe rendere più facile.

Penso che questo sia tutto ciò che serve?

SELECT       
     b.id IS NOT NULL as is_banned, -- The value of "is_banned" will be a boolean 

Non sono sicuro se è necessario il "NOT" o no, ma si otterrà un bool in entrambi i casi.

+0

Soluzione migliore della risposta accettata! – mes