Trong SQL Server 2008, làm cách nào tôi có thể nhận được tất cả các cột được đánh dấu là nullable trong lược đồ của chúng mặc dù không có bản ghi nào chứa NULL cho các cột đó?


7

Trong cơ sở dữ liệu kế thừa của tôi, rất nhiều thời gian lược đồ không cần thiết cho phép các mục rỗng cho các cột cụ thể. Để giúp tìm ra các cột cụ thể, tôi cần thực hiện một số truy vấn của SQL Server 2008 vượt quá trình độ chuyên môn của tôi. Mục đích của tôi là thắt chặt lược đồ một chút và tự cứu mình khỏi việc xử lý trường hợp null trong mã của tôi.

Một cách thô sơ (tùy chọn 1) để giúp tôi giải quyết vấn đề của mình là chỉ lấy tất cả các bản ghi (và chọn *) có chứa ít nhất một mục nhập null, sau đó quét mắt cho các cột không chứa mục nhập null. Tất nhiên tôi chỉ có thể sử dụng Where columnA IS NULL OR columnB IS NULL OR columnC IS NULL, nhưng điều này trở nên tẻ nhạt đối với các bảng có nhiều cột. Một số bảng trong cơ sở dữ liệu này chứa hơn hai mươi cột! Ngoài ra, có khoảng 500 bảng trong tổng số. Vì vậy, giải pháp chung là tốt nhất.

Dưới đây là ba tùy chọn cho câu trả lời sẽ thỏa mãn tôi:

  • Tùy chọn 1: "lấy cho tôi tất cả các bản ghi trong đó ít nhất một trong số các cột là null". Tôi sẽ quét mắt cho các cột không có mục rỗng.
  • Tùy chọn 2: Một câu trả lời thậm chí tốt hơn sẽ là một số tập lệnh nhận được danh sách các tên cột có chứa ít nhất một mục nhập null. Sau đó, tôi sẽ xem các cột nullable không có trong danh sách này theo cách thủ công.
  • Tùy chọn 3: Câu trả lời tốt nhất sẽ cho tôi một danh sách các tên cột được đánh dấu là nullable trong lược đồ của chúng mặc dù không có bản ghi nào tồn tại với mục nhập null trong các cột đó.

Cảm ơn!


Bạn có cần một câu trả lời chính xác?
Jack nói hãy thử topanswers.xyz

2
không, tôi là một lập trình viên thương mại. Tôi có thể tìm ra các chi tiết nhỏ.
IBC

3
Bây giờ tôi thấy câu hỏi của tôi không rõ ràng lắm ;-) Bạn có cần biết chính xác có bao nhiêu hàng có một nullnơi nào đó hoặc một ước tính sẽ làm gì không?
Jack nói hãy thử topanswers.xyz

Mục đích ban đầu của tôi là lấy một danh sách các hàng có mục rỗng trong đó và chỉ cần cuộn xuống danh sách kết quả và nhìn bằng mắt tôi cho những hàng không có hình chữ nhật null màu vàng nhỏ nào được đánh dấu là nullable trong lược đồ .
IBC

Vì vậy, tôi đoán những gì tôi thực sự muốn là một danh sách các cột được đánh dấu nullable mặc dù không có bản ghi nào chứa null cho cột đó.
IBC

Câu trả lời:


8

Câu trả lời của Martin Smith sẽ phục vụ rất tốt để giúp bạn có được tất cả các cột bạn cần cho toàn bộ cơ sở dữ liệu trong SQL 2008. Rất hay!

Đây là cách tôi đã làm trong những ngày trước khi SQL có CTE và PIVOT. Điều này sẽ tương thích với các phiên bản SQL cũ hơn, nơi giải pháp của Martin sẽ không hoạt động và vẫn hoạt động vào năm 2008, nhưng với hiệu suất kém hơn giải pháp của anh ấy.

USE MyDB

SET NOCOUNT ON

CREATE TABLE ##nullable  (
    ID INT IDENTITY(1,1),
    SchName VARCHAR(128),
    TblName VARCHAR(128),
    ColName VARCHAR(128),
    hasNulls BIT,
    PRIMARY KEY(ID)
    )

DECLARE @currTbl VARCHAR(128)
DECLARE @currCol VARCHAR(128)
DECLARE @currSch VARCHAR(128)
DECLARE @limit INT
DECLARE @i INT
DECLARE @sql NVARCHAR(4000)

INSERT INTO ##nullable (
    SchName,
    TblName,
    ColName,
    hasNulls
    )
SELECT
    c.TABLE_SCHEMA,
    c.TABLE_NAME,
    c.COLUMN_NAME,
    0 AS hasNulls
FROM INFORMATION_SCHEMA.COLUMNS c
INNER JOIN INFORMATION_SCHEMA.TABLES t
ON c.TABLE_CATALOG = t.TABLE_CATALOG
AND c.TABLE_NAME = t.TABLE_NAME
AND c.TABLE_SCHEMA = t.TABLE_SCHEMA
WHERE c.IS_NULLABLE = 'YES'
AND t.TABLE_TYPE = 'BASE TABLE'

SET @limit = (SELECT MAX(ID) FROM ##nullable)
SET @i = 1

WHILE @i <= @limit
BEGIN   
    SELECT @currSch = SchName,
        @currTbl = TblName,
        @currCol = ColName
    FROM ##nullable 
    WHERE ID = @i

    SET @sql = 'UPDATE ##nullable 
        SET hasNulls = 1
        WHERE ID = ' + CAST(@i AS VARCHAR(20)) + ' 
        AND EXISTS (SELECT 1 FROM ' + QUOTENAME(@currSch) + '.'+ QUOTENAME(@currTbl) + ' 
        WHERE ' + QUOTENAME(@currCol) + ' IS NULL)'

    EXEC(@sql)

    SET @i = @i + 1     
END

SELECT DISTINCT * FROM ##nullable 
WHERE hasNulls = 0  

DROP TABLE ##nullable

Câu trả lời tốt đẹp. Bạn thậm chí đã đánh rơi cái bàn tạm thời ở cuối để nó không làm phiền tôi lần thứ hai.
IBC

Có vẻ rất thanh lịch quá.
IBC

Tái tạo điều này ra khỏi đỉnh đầu của tôi và nhận ra có một phần của nó tôi quên mất trường học cũ. Chỉnh sửa để thay thế việc sử dụng sys. lượt xem với Information_SCHema để tương thích ngược tốt hơn.
Jonathan Van Matre

1
+1 Có nghĩa là nhiều truy vấn đối với cùng một bảng nhưng có thể bị đoản mạch nếu NULLtìm thấy a mà không phải quét toàn bộ bảng. BTW tốt hơn là sử dụng QUOTENAMEthay vì tự ghép các dấu ngoặc vuông vì nó tự động xử lý các tên đối tượng có chứa ]ký tự.
Martin Smith

Vâng, đối với SQL 2008, cách tiếp cận của bạn được tối ưu hóa tốt hơn nhiều. Rất thanh lịch, và tôi đang dán nó trong run rẩy. Và bắt tốt trên trường hợp cạnh QUOTENAME! Mã sửa đổi cho phù hợp.
Jonathan Van Matre

7

Bạn có thể sử dụng sys.sp_MSforeachtableđể lặp qua tất cả các bảng và xử lý như bên dưới (có thể cần điều chỉnh nếu bạn có tên đối tượng không chuẩn có chứa 'ký tự nhưng tôi sẽ để nó như một bài tập.)

CREATE TABLE #Results
(
object_name nvarchar(500),
column_name  nvarchar(500)
)

exec sys.sp_MSforeachtable '
IF EXISTS(
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(''?'') AND is_nullable=1)
BEGIN
RAISERROR(''Processing ?'',0,1) WITH NOWAIT


DECLARE @ColList nvarchar(max)
DECLARE @CountList nvarchar(max)

SELECT @ColList = ISNULL(@ColList + '','','''') + QUOTENAME(name),
       @CountList = ISNULL(@CountList + '','','''') + ''COUNT(*) 
          - COUNT(CASE WHEN '' + QUOTENAME(name) + '' IS NOT NULL THEN 1 END) AS '' + QUOTENAME(name)
FROM sys.columns WHERE object_id = OBJECT_ID(''?'')  AND is_nullable=1 

DECLARE @dynsql nvarchar(max)

SET @dynsql = ''
WITH T AS
(
SELECT 
        ''''?'''' AS table_name, 
        '' + @CountList + ''
FROM ?
)
INSERT INTO #Results
SELECT  table_name, col
FROM T
UNPIVOT (NullCount FOR col IN ('' + @ColList + '')) AS UnPvt
WHERE NullCount = 0
''

EXEC(@dynsql)
END
'


SELECT *
FROM #Results

DROP TABLE #Results

Lol @ để nó như một bài tập! Dù sao, điều này dường như có chứa logic tôi muốn. Tôi sẽ xem nếu tôi có thể làm cho nó hoạt động.
IBC

@IBC - Bạn có thực sự có bất kỳ tên bảng hoặc tên cột nào chứa 'ký tự không?
Martin Smith

+1 cho sự thanh lịch của giải pháp PIVOT và để giải quyết hoàn toàn vấn đề
Jonathan Van Matre

Tôi không nghĩ tên bảng của mình sử dụng '
IBC

Tôi chỉ thấy rằng tôi cần phải kiểm tra nó trên một cơ sở dữ liệu nhỏ hơn .. Việc này có thể mất một giờ để chạy trên cơ sở dữ liệu chính.
IBC

2

Có thể câu trả lời StackOverflow này sẽ giúp: /programming/63291/sql-select-columns-with-null-values-only

Có vẻ như nó được nhắm mục tiêu cho năm 2005, hy vọng nó hoạt động.

Theo yêu cầu, mở rộng (tôi nghĩ):

declare @col varchar(255), @cmd varchar(max)

DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = 'ADDR_Address'

OPEN getinfo

FETCH NEXT FROM getinfo into @col

WHILE @@FETCH_STATUS = 0
BEGIN
    SELECT @cmd = 'IF NOT EXISTS (SELECT top 1 * FROM ADDR_Address WHERE [' + @col + '] IS NOT NULL) BEGIN print ''' + @col + ''' end'
    EXEC(@cmd)

    FETCH NEXT FROM getinfo into @col
END

CLOSE getinfo
DEALLOCATE getinfo

Thay thế ADDR_Address bằng tên bảng của bạn.


2

Trong SQL Server, có một số khung nhìn hệ thống được sử dụng đặc biệt để mô tả các định nghĩa đối tượng: chúng là Information_SCHema.Tables, Cột, v.v.

Trong trường hợp này, chỉ trả lời câu hỏi cuối cùng ("danh sách các tên cột được đánh dấu là nullable trong lược đồ của chúng ..."), tôi muốn nói rằng bạn cần một cái gì đó giống như truy vấn sau:

use DBTest; GO;

SELECT
    c.TABLE_CATALOG as DatabaseName,
    c.TABLE_SCHEMA as SchemaName,
    c.TABLE_NAME as TableName,
    c.COLUMN_NAME as ColumnName,
    c.IS_NULLABLE as IsNullable 
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_CATALOG = 'DbTest'
and c.TABLE_SCHEMA = 'dbo'
AND c.TABLE_NAME = 'TableTest'
and c.IS_NULLABLE = 'YES'

Điều này sẽ giúp bạn có một danh sách các cột cho một db và bảng cụ thể. Xóa bộ lọc bảng và bạn sẽ có kết quả bạn muốn cho db hoàn chỉnh. Các khung nhìn Information_SCHema chỉ liên quan đến cơ sở dữ liệu hiện tại đang sử dụng, vì vậy bạn không thể sử dụng nó cho tất cả các dbs cùng một lúc, trừ khi bạn thực hiện một sql động.


Điều này rất hữu ích, nhưng tôi vẫn cần lọc danh sách mà nó chỉ trả về những cột không có giá trị VÀ không có bản ghi nào trong db nơi cột đó chứa giá trị null.
IBC

Tôi chỉ theo dõi một phần câu hỏi của bạn, xin lỗi :-). Sau đó, bắt buộc phải tạo một sql động để duyệt qua danh sách các bảng và cột đó và tính tổng tất cả các hàng của bảng theo cột đó và cuối cùng chỉ hiển thị những hàng có tổng không rỗng.
Mary
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.