Ho creato una procedura memorizzata per te.
Questa procedura esamina il meta MSSQL per creare una stringa SQL dinamica che restituisce un risultato contenente i nomi di colonna N
e i loro valori V
e la chiave di riga corrispondente K
da cui è stato recuperato quel valore, per una tabella specificata.
Quando viene eseguito, i risultati vengono archiviati in una tabella temporanea globale denominata ##ColumnsByValue, che può quindi essere interrogata direttamente.
Crea il GetColumnsByValue
stored procedure, eseguendo questo script:
-- =============================================
-- Author: Ben Roberts ([email protected])
-- Create date: 22 Mar 2013
-- Description: Returns the names of columns that contain the specified value, for a given row
-- =============================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID ( 'dbo.GetColumnsByValue', 'P' ) IS NOT NULL
DROP PROCEDURE dbo.GetColumnsByValue;
GO
CREATE PROCEDURE dbo.GetColumnsByValue
-- Add the parameters for the stored procedure here
@idColumn sysname,
@valueToFind nvarchar(255),
@dbName sysname,
@tableName sysname,
@schemaName sysname,
@debugMode int = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @SQL nvarchar(max);
DECLARE @SQLUnion nvarchar(max);
DECLARE @colName sysname;
DECLARE @dbContext nvarchar(256);
DECLARE @Union nvarchar(10);
SELECT @dbContext = @dbName + '.' + @schemaName + '.sp_executeSQL';
SELECT @SQLUnion = '';
SELECT @Union = '';
IF OBJECT_ID ( 'tempdb..##GetColumnsByValueIgnoreList') IS NULL -- no columns to ingore have been specified, need to create an empty list.
BEGIN
CREATE TABLE ##GetColumnsByValueIgnoreList (column_name nvarchar(255));
END
DECLARE DBcursor CURSOR FOR
SELECT
COLUMN_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = @tableName
AND
TABLE_SCHEMA = @schemaName;
OPEN DBcursor;
FETCH DBcursor INTO @colName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
IF (
@colName != @idColumn
AND
@colName NOT IN (SELECT column_name FROM ##GetColumnsByValueIgnoreList)
)
BEGIN
SELECT @SQL = 'SELECT '[email protected]+' as K, '''[email protected]+''' as N, ' [email protected]+ ' as V FROM ' + @dbName + '.' + @schemaName + '.' + @tableName;
--PRINT @SQL;
SELECT @SQLUnion = @SQL + @Union + @SQLUnion;
SELECT @Union = ' UNION ';
END
FETCH DBcursor INTO @colName;
END; -- while
CLOSE DBcursor; DEALLOCATE DBcursor;
IF (@debugMode != 0)
BEGIN
PRINT @SQLUnion;
PRINT @dbContext;
END
ELSE
BEGIN
-- Delete the temp table if it has already been created.
IF OBJECT_ID ('tempdb..##ColumnsByValue') IS NOT NULL
BEGIN
DROP TABLE ##ColumnsByValue
END
-- Create a new temp table
CREATE TABLE ##ColumnsByValue (
K nvarchar(255), -- Key
N nvarchar(255), -- Column Name
V nvarchar(255) -- Column Value
)
-- Populate it with the results from our dynamically generated SQL.
INSERT INTO ##ColumnsByValue EXEC @dbContext @SQLUnion;
END
END
GO
L'SP accetta diversi input come parametri, questi sono spiegati nel codice seguente.
Nota anche che ho fornito un meccanismo per aggiungere una "lista di esclusione" come input:
- Questo ti permette di elencare tutti i nomi di colonna che non dovrebbero essere inclusi nei risultati.
- NON è necessario aggiungere la colonna che stai utilizzando come chiave, ovvero il
row_id
dalla tua struttura di esempio. - DEVI includere altre colonne che non siano
varchar
poiché questi causeranno un errore (poiché l'SP esegue semplicemente unvarchar
confronto su tutte le colonne che guarda). - Questo viene fatto tramite una tabella temporanea che devi creare/compilare
- La struttura della tabella di esempio suggerisce che la tabella contiene solo colonne di interesse, quindi questo potrebbe non essere applicabile a te.
Ho incluso un codice di esempio su come farlo (ma fallo solo se necessario a):
IF OBJECT_ID ( 'tempdb..##GetColumnsByValueIgnoreList') IS NOT NULL
BEGIN
DROP TABLE ##GetColumnsByValueIgnoreList;
END
CREATE TABLE ##GetColumnsByValueIgnoreList (column_name nvarchar(255));
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('a_column');
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('another_column');
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('yet_another_column');
Ora, per avviare la procedura che crea la tua tabella temporanea dei risultati, usa il codice seguente (e modificalo come appropriato, ovviamente).
-- Build the ##ColumnsByValue table
EXEC dbo.GetColumnsByValue
@idColumn = 'row_id', -- The name of the column that contains your row ID (eg probably your PK column)
@dbName = 'your_db_name',
@tableName = 'your_table_name',
@schemaName = 'dbo',
@debugMode = 0 -- Set this to 1 if you just want a print out of the SQL used to build the temp table, to 0 if you want the temp table populated
Questo ti lascia con ##ColumnsByValue
, su cui puoi eseguire qualsiasi ricerca ti serva, ad esempio:
select * from ##ColumnsByValue WHERE v = 'luxury' and k = 5 --some_row_id
Dovresti rieseguire la procedura memorizzata (e, se pertinente, creare/modificare la tabella dell'elenco di esclusione prima di essa) per ogni tabella che desideri esaminare.
Una preoccupazione con questo approccio è che la lunghezza di nvarchar potrebbe essere superata nel tuo caso. Ci proveresti. è necessario utilizzare un tipo di dati diverso, ridurre le lunghezze dei nomi delle colonne, ecc. Oppure suddividerlo in passaggi secondari e unire i risultati per ottenere il set di risultati che stai cercando.
Un'altra preoccupazione che ho è che questo è completamente eccessivo per il tuo particolare scenario, in cui una finestra da script a query una tantum ti fornirà le basi di ciò di cui hai bisogno, quindi alcune modifiche intelligenti del testo, ad esempio Notepad ++, ti daranno tutto il modo lì ... e quindi questo problema probabilmente (e abbastanza ragionevolmente) ti scoraggerà a farlo in questo modo! Ma è una buona domanda generica, e quindi merita una risposta per chiunque sia interessato al futuro;-)