2009-09-03 12 views
9

Sto lavorando con una tabella in MySQL che contiene le seguenti colonne:corrispondenza di un valore a più colonne (in una dichiarazione) da una tabella utilizzando MySQL

id, january, february, march, april, etc 

I dati nella tabella assomiglia a questo:

aa, 0, 0, 1, 0 
ab, 1, 0, 1, 0 
ac, 1, 1, 0, 0 
ad, 1, 1, 1, 0 

Per interrogare, ho potuto facilmente fare questo:

select * from table where january = 1 and february = 1 

Il risultato sarebbe:

ac, 1, 1, 0, 0 
ad, 1, 1, 1, 0 

voglio sapere se c'è un modo per farlo in questo modo:

select * from table where table.columns = 1 

voglio usare colonne della tabella nell'espressione senza in realtà specificare i nomi manualmente (digitandoli out).

Bonus (+1) domanda:
Potrebbe essere fatto utilizzando Partita/Contro questo modo:

select * from table 
where 
(
    match (somehow,get,the,table,columns,I,need,here) 
    against (1 in boolean mode) 
) 

Grazie per il vostro tempo! :)

+0

Che cosa testate esattamente nella clausola "WHERE table.colmuns = 1"? Vuoi i registri in cui esattamente uno di gennaio, febbraio ecc. È uno? – Martijn

+0

Voglio ottenere tutte le righe che contengono 1 in una qualsiasi delle colonne della tabella. –

risposta

4

Devi usare una dichiarazione preparata, perché ciò che si vuole fare può essere fatto solo con SQL dinamico:

SET @stmt = 'SELECT * FROM YOUR_TABLE WHERE 1 = 1 ' 
SET @stmt = CONCAT(@stmt, (SELECT CONCAT_WS(' AND ', CONCAT(column_name, ' = 1 ')) 
          FROM INFORMATION_SCHEMA.COLUMNS 
          WHERE table_name = 'YOUR_TABLE' 
          AND table_schema = 'db_name' 
          AND column_name NOT IN ('id'))); 

PREPARE stmt FROM @stmt; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

La prima istruzione SET costruisce un'istruzione SELECT di base; la porzione "1 = 1" è proprio lì per semplificare la concatenazione di "AND column = 1"

La seconda istruzione SET concatena il contenuto della query per ottenere l'elenco di colonne in base al nome della tabella alla fine del stringa nella prima istruzione SET. L'idea è che questo:

SELECT CONCAT_WS(' AND ', CONCAT(column_name, ' = 1 ')) 
    FROM INFORMATION_SCHEMA.COLUMNS 
WHERE table_name = 'YOUR_TABLE' 
    AND table_schema = 'db_name' 
    AND column_name NOT IN ('id') 

... restituirà una riga che assomiglia a "AND january = 1 AND february = 1 ...". Dovresti aggiornare la clausola NOT IN se ci sono altre colonne che non vuoi nella clausola WHERE.

Il resto è solo materiale di istruzioni standard, e tutto ciò dovrebbe avvenire all'interno di una stored procedure.

+0

Penso che l'OP vorrebbe "OR" invece di "AND". Inoltre, non dimenticare di controllare 'schema_name' nello schema delle informazioni, nel caso in cui ci sia una tabella con lo stesso nome in un altro schema. –

+0

@Bill: Thx, ha aggiunto il controllo mancante per il nome dello schema. Sei sicuro di usare 'OR's? L'OP dice esplicitamente "gennaio = 1 e febbraio = 1". –

0

È possibile utilizzare i vettori in MySQL:

select * from table where (january, february) = (1, 1) 

Attenzione di diversi server e client regole di confronto per le colonne di testo, probabilmente avrete bisogno di specificare le regole di confronto in modo esplicito, allora.

+0

Non è quello che sto cercando, non voglio specificare i nomi delle colonne. Un buon concetto, però, i vettori sono utili. –

+0

Non molto chiaro allora. Vuoi usare le colonne della tabella nell'espressione senza specificarne effettivamente i nomi? Forse dovresti prima eseguire 'DESCRIBE table' per ottenere i metadati della tabella e quindi usare i campi nelle query successive? – pingw33n

+0

Aggiornata la domanda. Spero sia chiaro ora :) –

0

A mio parere questo è causato da quello che sembra essere cattiva progettazione tavolo (sto indovinando che è solo un esempio per semplicemente il vostro problema, ma recano con me, e credo che questo concetto potrebbe essere modellato migliore.
Qui sono le tabelle:

Things  Things_Months  Months 
    thing_id  thing_id   Month_id 
    thing_info  month_id   Month_Name 
        thing_month_id  order_field 

e qui sarebbe sql:

select thing_info, month_name 
    from things, things_months, months 
    where things.thing_id = things_months.thing_id 
    and things_months.month_id = months.month_id 
    order by things.things_info, months.order_field 

i risultati sarebbero

thingy 1, January 
    thingy 1, February 
    thingy 2, April 
    thingy 3, November 
    thingy 3, December 
+0

Jay, hai ragione, è a causa del design del tavolo poveri. Tuttavia, non sono autorizzato a modificare la struttura della tabella. –

0
select * from table where 1 in (january, february) 
+0

No, non è neanche quello. Grazie per il suggerimento però. –

1

Capisco quello che Mr.Smith sta cercando di fare.

Si tratta di 12 righe x 4 colonne rispetto a 1 riga x 12 colonne.

L'ex struttura della tabella sarebbe qualcosa di simile:

id, di qualcuno id, il mese, il valore x 12 al mese

1, 101, january, 1 
2, 101, february, 1 
3, 101, march, 0 
etc.. 

La corrispondente istruzione SQL per questo sarebbe:

$sqlQuery = "SELECT month FROM my_month_table WHERE value = 1"; 

Che cosa sto indovinando Mr.Smith sta cercando:

id, id di qualcuno, gennaio, febbraio, marzo ...

$sqlQuery = "SELECT corrensponding_column_names_to_where_clause FROM my_month_table WHERE column_value = 1"; 
1

puoi farlo utilizzando partita ... contro.

In tal caso la tabella deve essere la tabella MyISAM ed è necessario creare indice FULLTEXT incluse le colonne richieste.

0

Come risolvere il problema con una VISTA? Dati

CREATE TABLE `d001ab05`.`months` (
`id` INT NOT NULL , 
`jan` BOOL NOT NULL , 
`feb` BOOL NOT NULL , 
`mar` BOOL NOT NULL , 
`apr` BOOL NOT NULL , 
`may` BOOL NOT NULL , 
`jun` BOOL NOT NULL , 
`jul` BOOL NOT NULL , 
`aug` BOOL NOT NULL , 
`sep` BOOL NOT NULL , 
`oct` BOOL NOT NULL , 
`nov` BOOL NOT NULL , 
`dec` BOOL NOT NULL , 
PRIMARY KEY (`id`) 
) ENGINE = InnoDB; 

Inserire:

INSERT INTO `d001ab05`.`months` (
`id`, `jan`, `feb`, `mar`, `apr`, `may`, `jun`, 
`jul`, `aug`, `sep`, `oct`, `nov`, `dec` 
) VALUES (
'1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' 
), (
'2', '1', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' 
), (
'3', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' 
), (
'4', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1' 
); 

Visualizza con Seleziona:

CREATE OR REPLACE VIEW `moncase` AS 
SELECT id, 
CASE WHEN `jan` =1 OR `feb` =1 OR `mar` =1 OR `apr` =1 OR `may` =1 OR 
`jun` =1 OR `jul` =1 OR `aug` =1 OR `sep` =1 OR `oct` =1 OR `nov` =1 OR `dec` =1 
THEN 1 ELSE 0 END AS or_over_months 
FROM months; 

Seleziona:

SELECT * FROM `moncase` WHERE `or_over_months` = 1; 

Risultato:

id | or_over_months 
1 | 1 
2 | 1 
4 | 1 
1

Tentare di creare vista

CREATE VIEW v_months 
AS 
SELECT *, CONCAT(CAST(jan AS CHAR(1)), 
        CAST(feb AS CHAR(1)), 
        CAST(mar AS CHAR(1)), 
        ...) AS all 
FROM months 

Otterrete qualcosa di simile:

aa, 0, 0, 1, 0, 0010 
ab, 1, 0, 1, 0, 1010 
ac, 1, 1, 0, 0, 1100 
ad, 1, 1, 1, 0, 1110 

E poi è possibile interrogare

SELECT * FROM v_months WHERE all = '100110010101' 

Oppure, se volete query "ottenere tutte le righe , dove feb = 1 ", puoi scrivere così:

SELECT * FROM v_months WHERE all LIKE '_1____________'  

dove '_' corrisponde esattamente a un carattere.

+0

L'utilizzo della funzione e il filtraggio dei risultati saranno un disastro per le prestazioni. Il database dovrà valutare la funzione per tutte le righe nella tabella e quindi confrontare l'output di quello con la stringa a cui si sta confrontando. L'utilizzo dell'output di funzioni, direttamente o indirettamente, in un predicato di query (clausola WHERE) è un no-no generale per le prestazioni. – dcrosta

0

Quello che ti serve è un'operazione senza perno. Microsoft SQL Server supporta PIVOT e UNPIVOT come estensioni a SQL standard. Non conosco altre marche di RDBMS che supportano la funzionalità di pivot/unpivot integrata. Certamente MySQL non supporta questo.

Non è possibile utilizzare FULLTEXT ricerca in questo caso, perché, come la documentazione say:

indici full-text possono essere utilizzati solo con le tabelle MyISAM, e possono essere creati solo per CHAR, VARCHAR, o Colonne di testo.

E non si dovrebbe alleviare dalla necessità di specificare le colonne in ogni caso, perché il predicato MATCH() ha bisogno di elencare tutti i colonne nell'indice full-text.

Se non è possibile ristrutturare la tabella per memorizzare una riga per mese o una singola colonna per codificare tutti i 12 mesi, è necessario generare SQL dinamico.

Problemi correlati