2016-06-26 4 views
9

Хорошо, 4 часа кодирования и всего 6 часов поиска ... и мне не лучше, чем когда я начал. Вот моя проблема. У меня есть таблица (tmpShell), и она имеет 12 столбцов. Это базовая таблица без ограничений - используется для временной отчетности. Когда мы вставляем данные, я должен извлечь идентификационный номер (PatientId) и все столбцы NAMES, где значение для этого PatientId равно null.Выбор имен столбцов, где значения NULL

Пример:

 
PatientId    Fname    Lname      DOB 
123455       Sam      NULL       NULL
2345455      NULL     Doe        1/1/1980
09172349     John     Jone       NULL

То, что я хочу вернуться в:

 
PatientId    ErrorMsg 
123455       Lname,DOB
2345455      Fname
09172349     DOB

Конечно, если все столбцы имеют значения, ErrorMsg будет нулевым.

Я пробовал и проваливал около 300 различных фрагментов кода, но это, по-видимому, самое близкое, что я могу получить. К сожалению, это просто возвращает КАЖДОЙ столбец, а не нули.

 
    ALTER PROC [sp_aaShowAllNullColumns] 
     @tableName VARCHAR(255) 
    AS 
     BEGIN 
      SET NOCOUNT ON;

DECLARE @sql NVARCHAR(4000); DECLARE @cols NVARCHAR(4000); DECLARE @tcols TABLE ([colbit] NVARCHAR(255)); --DECLARE @tablename VARCHAR(255) = 'tmpShell'; INSERT @tcols SELECT 'count(' + [columns].[name] + ') as ' + [columns].[name] + ', ' AS [colbit] FROM [sys].[columns] WHERE [columns].[object_id] = OBJECT_ID(@tableName); SELECT @cols = COALESCE(@cols, ', ', '') + [@tcols].[colbit] FROM @tcols; SELECT @cols = SUBSTRING(@cols, 1, (LEN(@cols) - 1)); SELECT @cols = ISNULL(@cols, ''); SELECT @sql = 'select patientid, count(*) as Rows' + @cols + ' from ' + @tableName + ' group by patientid having count(*) > 0'; CREATE TABLE [tmpShell2] ( [patientid] VARCHAR(15) ,[Rows] CHAR(2) ,[Rn] CHAR(2) ,[patId] CHAR(2) ,[fname] CHAR(2) ,[lname] CHAR(2) ,[dob] CHAR(2) ,[addr1] CHAR(2) ,[city] CHAR(2) ,[state] CHAR(2) ,[zip] CHAR(2) ,[country] CHAR(2) ,[psite] CHAR(2) ,[csite] CHAR(2) ,[ssite] CHAR(2) ,[scode] CHAR(2) ,[sfid] CHAR(2) ,[taskid] CHAR(2) ,[errormsg] CHAR(2) ); INSERT INTO [tmpShell2] EXEC [sys].[sp_executesql] @sql; DECLARE @tbl VARCHAR(255) = 'tmpShell2'; SELECT DISTINCT [TS].[patientid] , STUFF(( SELECT DISTINCT ', ' + [C].[name] FROM [tmpShell2] AS [TS2] JOIN [sys].[columns] AS [C] ON [C].[object_id] = OBJECT_ID(@tbl) WHERE [C].[name] NOT IN ('SFID', 'TaskId', 'ErrorMsg') AND [C].[name] IS NOT NULL FOR XML PATH('') ), 1, 1, '') FROM [tmpShell2] AS [TS]; DROP TABLE [dbo].[tmpShell2]; END; GO EXEC [sp_aaShowAllNullColumns] 'tmpShell'; </pre>
+0

Вам нужно сделать это по неизвестному количеству столов или только одному? –

+0

Какова вероятность того, что столбцы (кроме ключа) в этой таблице изменятся или что будут столбцы, в которых вам все равно, есть ли нуль? –

+0

Да, количество таблиц неизвестно, а столбцы будут отличаться от таблицы к таблице. Вероятность того, что все изменится, очень тонкая. – RazorSharp

ответ

3

Как насчет этого?

SELECT 
a.PatientID 
, CASE a.tmpCol 
    WHEN '' THEN NULL 
    ELSE STUFF(a.tmpCol,1,1,'') 
END AS ErrorMsg 
FROM 
(
SELECT 
    PatientID 
    , CASE WHEN FirstName IS NULL THEN ',FirstName' ELSE '' END 
    + CASE WHEN LastName IS NULL THEN ',LastName' ELSE '' END 
    + CASE WHEN DOB IS NULL THEN ',DOB' ELSE '' END AS tmpCol 
FROM 
    <tableName> 
) a; 
+0

Я использую это сейчас, но мне бы хотелось, чтобы более динамичный способ был гибким для разных имен таблиц и столбцов. – RazorSharp

+0

Я добавил ответ ниже, который я считаю гибким для имен таблиц и столбцов. – DVT

8

Я думаю, вы над сложными вещами.

Вы можете попробовать использовать CASE EXPRESSION:

SELECT t.patientID, 
     CASE WHEN t.fname is NULL THEN 'Fname,' ELSE '' END + 
     CASE WHEN t.Lname is NULL THEN 'Lname,' ELSE '' END + 
     CASE WHEN t.DOB is NULL THEN 'DOB,' ELSE '' END 
     ..... as ErrorMsg 
FROM YourTable t 

Это приведет с ненужной запятой в конце errorMsg, чтобы справиться с этим вы можете сделать это:

 REPLACE(CASE... + 
       CASE... + 
       CASE WHEN t.DOB is NULL THEN 'DOB,' ELSE '' END 
       ..... + ' ') ', ','') as ErrorMsg 

Это сделает последняя запятая уникальна, потому что у нее будет пространство, связанное с ней, и будет убедиться, что только она будет удалена.

+0

Как вы планируете обрабатывать случай, когда для данной записи появляется только «Fname»? Тогда у него будет висячая запятая. –

+0

@TimBiegeleisen Вот так .. – sagi

2

Вы можете использовать сводный запрос, чтобы получить желаемый результат. Следующий запрос должен приблизиться к вашему желаемому результату:

SELECT PatientId, 
    CONCAT(CASE WHEN Fname IS NULL THEN 'Fname ' ELSE '' END, 
      CASE WHEN Lname IS NULL THEN 'Lname ' ELSE '' END, 
      CASE WHEN DOB IS NULL THEN 'DOB' ELSE '' END) 
FROM yourTable 
+0

Он хотел, чтобы список с запятыми, 14 столбцов с запятой не читаются. – sagi

1

Вот SQLfiddle на основе https://stackoverflow.com/a/38036046/2314737 с обработкой запятых

http://sqlfiddle.com/#!9/708796/1

SELECT PatientId, 
    REPLACE(RTRIM(CONCAT(CASE WHEN Fname IS NULL THEN 'Fname ' ELSE '' END, 
      CASE WHEN Lname IS NULL THEN 'Lname ' ELSE '' END, 
      CASE WHEN DOB IS NULL THEN 'DOB' ELSE '' END)), 
      ' ',',') 
FROM YourTable 
+0

привет @sagi Спасибо за ваши отзывы. Когда все поля не являются NULL, будет пустое пространство, я думаю, нужно сделать еще один выбор в этом выборе, чтобы исключить строки с пустым пространством. – user2314737

+0

@sagi не делает RTRIM до того, как REPLACE позаботится об этом? – user2314737

+0

Да, я пропустил это извините. – sagi

0

Это хранимая процедура, которая будет принимать во имя схемы, имя таблицы и столбца, а затем вы получите желаемый результат.

ALTER PROCEDURE [dbo].[DynamicErrorProducing] 
@schema_name NVARCHAR(100), 
@table_name NVARCHAR(100), 
@column_name NVARCHAR(100) 
AS 
BEGIN 
DECLARE @countTable TINYINT; 
DECLARE @countColumn TINYINT; 
DECLARE @string NVARCHAR(MAX); 
DECLARE @sqlString NVARCHAR(MAX); 

SET @countTable=0; 

SELECT 
    @countTable=COUNT(*) 
FROM 
    sys.tables 
WHERE 
    SCHEMA_NAME(schema_id)[email protected]_name 
    AND [email protected]_name; 

-- If there is no table as described, quit with an error 
IF (@countTable = 0) 
    RETURN 0; 

SET @countColumn=0; 

SELECT 
    @countColumn=COUNT(*) 
FROM 
    sys.columns 
WHERE 
    object_id = OBJECT_ID(@schema_name+'.'[email protected]_name) 
    AND [email protected]_name; 

IF (@countColumn<> 1) 
    RETURN; 

SELECT 
    @countColumn=COUNT(*) 
FROM 
    sys.columns 
WHERE 
    object_id = OBJECT_ID(@schema_name+'.'[email protected]_name) 
    AND name<>@column_name; 

IF (@countColumn<1) 
    RETURN; 

SELECT @string=STUFF(
    (
    SELECT 
     '+ CASE WHEN '+name+' IS NULL THEN '''' ELSE '','+name+''' END ' 
    FROM 
     sys.columns 
    WHERE 
     object_id = OBJECT_ID(@schema_name+'.'[email protected]_name) 
     AND name<>@column_name 
    FOR XML PATH('')) 
    ,1,2,''); 


SET @sqlString=N' 
SELECT 
    a.'[email protected]_name+' 
    , CASE WHEN a.tmpCol='''' THEN NULL ELSE STUFF(a.tmpCol,1,1,'''') END AS ErrMsg 
FROM 
(
SELECT 
    '[email protected]_name+' 
    ,'[email protected]+' AS tmpCol 
FROM 
    '[email protected]_name+'.'[email protected]_name+' 
) a'; 

EXEC sp_executesql 
    @[email protected]; 

END 


GO 
Смежные вопросы