2015-09-17 23 views
6

Ho una tabella che memorizza 1 riga per 1 sondaggio.
Ogni sondaggio ha ottenuto circa 70 domande, ciascuna colonna presente 1 domandaUnire tabelle per nome colonna, convertire stringa in nome colonna

SurveyID Q1, Q2 Q3 ..... 
1   Yes Good Bad ...... 

voglio ruotare questo modo si legge

SurveyID Question Answer 
1  Q1  Yes 
1  Q2  Good 
1  Q3  Bad 
...  ...  ..... 

Io uso {croce applicare} per raggiungere questo obiettivo

SELECT t.[SurveyID] 
    , x.question 
    , x.Answer 
    FROM tbl t 
    CROSS APPLY 
    (
    select 1 as QuestionNumber, 'Q1' as Question , t.Q1 As Answer union all 
    select 2 as QuestionNumber, 'Q2' as Question , t.Q2 As Answer union all 
    select 3 as QuestionNumber, 'Q3' as Question , t.Q3 As Answer) x 

Questo funziona ma non voglio farlo 70 volte quindi ho questa istruzione select

select ORDINAL_POSITION 
    , COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = mytable 

Questo mi dà l'elenco di colonna e posizione della colonna nella tabella. Quindi spero di poter unire in qualche modo la 2a affermazione con la prima affermazione dove per nome della colonna. Tuttavia sto confrontando il contenuto all'interno di una colonna e l'intestazione di una colonna qui. È fattibile? C'è un altro modo per raggiungere questo?

Spero che tu possa guidarmi per favore?

Grazie

+0

non può partecipare al set di risultati a meno che non si utilizzi sql dinamico. più facile usare l'istruzione select per rendere le 70 istruzioni select e poi copiarle con un editor. Questo ti farà risparmiare un po 'di battitura. – Hogan

risposta

5

Invece di Croce Applica si dovrebbe usare UNPIVOT per questa query ....

SQL Fiddle

Server Setup Schema MS SQL 2008:

CREATE TABLE Test_Table(SurveyID INT, Q1 VARCHAR(10) 
            , Q2 VARCHAR(10), Q3 VARCHAR(10), Q4 VARCHAR(10)) 

INSERT INTO Test_Table VALUES 
(1 , 'Yes', 'Good' , 'Bad', 'Bad') 
,(2 , 'Bad', 'Bad' , 'Yes' , 'Good') 

Richiesta 1:

SELECT SurveyID 
     ,Questions 
     ,Answers 
FROM Test_Table t 
UNPIVOT (Answers FOR Questions IN (Q1,Q2,Q3,Q4))up 

Results:

| SurveyID | Questions | Answers | 
|----------|-----------|---------| 
|  1 |  Q1 |  Yes | 
|  1 |  Q2 | Good | 
|  1 |  Q3 |  Bad | 
|  1 |  Q4 |  Bad | 
|  2 |  Q1 |  Bad | 
|  2 |  Q2 |  Bad | 
|  2 |  Q3 |  Yes | 
|  2 |  Q4 | Good | 
+0

L'ho svalutato perché è un consiglio eccellente: UNPIVOT è molto più ordinato di CROSS APPLY ed è concepito proprio per questa situazione. Tuttavia, questo non risponde alla domanda in quanto l'OP vuole evitare di scrivere SQL per coprire 70 colonne; questo richiede ancora che le colonne vengano digitate. (Accetto ci sono scorciatoie per questo, ad esempio il trascinamento dalla cartella Colonne in Esplora oggetti.) –

+0

Ho anche esplorato questa funzione, ma ho ottenuto alcune tabelle nella struttura come questa e il numero di domande è variabile. Mi chiedo se c'è un modo in cui non ho bisogno di digitare Q1-Q70 o così via? Grazie per l'aiuto. – PeddiePooh

+0

@PeddiePooh la mia risposta alternativa dovrebbe darti un modo per farlo, l'hai visto? –

0

Se avete bisogno di eseguire questo tipo di operazione per un sacco di tavoli simili che hanno numeri diversi di colonne, un approccio UNPIVOT solo può essere faticoso perché si deve modificare manualmente l'elenco di colonne (Q1,Q2,Q3,etc) ogni volta.

La query basata su CROSS APPLY nella domanda presenta anche altri inconvenienti.

La soluzione a questo, come hai intuito, riguarda l'utilizzo delle meta-informazioni gestite dal server per indicare l'elenco di colonne su cui è necessario operare. Tuttavia, piuttosto che richiedere un tipo di unire come sospetti, ciò che è necessario è SQL dinamico, ovvero una query SQL che crea al volo un'altra query SQL.

Ciò avviene essenzialmente concatenando le informazioni stringa (varchar) nella parte SELECT della query, inclusi i valori delle colonne che sono disponibili nelle clausole FROM (e join).

Con gli approcci di SQL dinamico (DSQL), si utilizzano spesso i metatables di sistema come punto di partenza.INFORMATION_SCHEMA esiste in alcune versioni di SQL Server, ma è meglio usare lo Object Catalog Views per questo.

Una soluzione prototipo DSQL per generare il codice per il vostro approccio CROSS APPLY sarebbe simile a questa:

-- Create a variable to hold the created SQL code 
-- First, add the static code at the start: 
declare @SQL varchar(max) = 
' SELECT t.[SurveyID] 
    , x.question 
    , x.Answer 
    FROM tbl t 
    CROSS APPLY 
    (
' 

-- This syntax will add to the variable for every row in the query results; it's a little like looping over all the rows. 
select @SQL += 
    'select ' + cast(C.column_id as varchar) 
    + ' as QuestionNumber, ''' + C.name 
    + ''' as Question , t.' + C.name 
    + ' As Answer union all 
    ' 
from sys.columns C 
inner join sys.tables T on C.object_id=T.object_id 
where T.name = 'MySurveyTable' 

-- Remove final "union all", add closing bracket and alias 
set @SQL = left(@SQL,len(@SQL)-10) + ') x' 

print @SQL 

-- To also execute (run) the dynamically-generated SQL 
-- and get your desired row-based output all at the same time, 
-- use the EXECUTE keyword (EXEC for short) 

exec @SQL 

Un approccio simile potrebbe essere utilizzato per scrivere in modo dinamico SQL per l'approccio UNPIVOT.

+0

Nota Ho scritto questo in fretta senza la possibilità di testare su una vera casella di SQL Server; se qualcuno capita errori di battitura o bug minori, ti preghiamo di correggerli, con le mie scuse ;-) –