Làm thế nào để hiển thị kết quả MS SQL theo chiều dọc?


8

Đây là những gì tôi đã nhận được khi thực hiện các truy vấn trong sqlcmd:

1> SELECT 1,2,3,4
2> GO

----------- ----------- ----------- -----------
          1           2           3           4

(1 rows affected)

Mặc dù trong trường hợp kết quả dài hơn, định dạng đầu ra này không thể đọc được bằng con người, vì nó được bọc trong thiết bị đầu cuối.

Làm thế nào để hiển thị kết quả theo chiều dọc (tương đương \Gtrongmysql )? Hoặc theo một cách khác mà con người có thể đọc được?


2
bạn có phải sử dụng sqlcmd không? Tôi thấy mssql-cli nói "Định dạng đẹp cho kết quả truy vấn, bao gồm Định dạng dọc" blog.technet.microsoft.com/datapl platforminsider / 2017/12/12 / Khăn
Martin Smith

1
@MartinSmith Có, tôi có thể sử dụng các lựa chọn thay thế, cho đến nay tôi có thể cài đặt chúng dễ dàng trên Linux. (Đúng, đã cài đặt nó khá nhanh, nhưng có một số lỗi CoreCLR, sẽ khai thác nó)
kenorb

Mát mẻ. Nếu bạn làm cho nó hoạt động sẽ tốt để xem ảnh chụp màn hình của định dạng dọc này.
Martin Smith

Câu trả lời:


5

Kết quả mong đợi khi bạn sử dụng SELECT F1, F2, F2là lấy một cột cho mỗi trường trong câu CHỌN.

SELECT '1' + CHAR(13) + '2' + CHAR(13) + '3' + CHAR(13)

------
1
2
3


(1 row(s) affected)

5

Bạn có thể sử dụng UNION:

select 1 union select 2 union select 3 union select 4

Các kết quả:

-----------
1
2
3
4

(4 rows affected)

4

Tôi đã tìm thấy một cách tiếp cận T-SQL thuần túy để hiển thị kết quả XÁC NHẬN trong cửa sổ Kết quả . Nó liên quan đến một thủ tục được lưu trữ tùy chỉnh (sp_SHOWDOWN) mà tôi đang sao chép từ liên kết này. Bạn có thể chơi xung quanh với nó để xem nếu nó giúp.

Tác giả chỉ ra một vài hạn chế:

  • Truy vấn có thể phức tạp đến mức cần thiết với càng nhiều phép nối, tuy nhiên tên cột phải là duy nhất do bảng tạm thời.
  • Sẽ rất chậm nếu bạn đang cố gắng trả lại nhiều hồ sơ. Hoạt động tốt nhất cho các truy vấn trả về 10 hoặc ít hơn các bản ghi.
  • Nó hiển thị ĐỐI TƯỢNG cho các trường văn bản và hình ảnh

Dưới đây là một mô tả ngắn gọn ( lấy từ bài viết ):

Quy trình này sẽ cho phép bạn hiển thị kết quả theo chiều dọc (xuống) thay vì trên màn hình. Thật tuyệt vời khi bạn đang xử lý một truy vấn có 50 cột và chỉ một vài bản ghi

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
/********************************************************************************************************
** NAME: sp_ShowDown
**
** DESC: Display (SHOWs) the results of a SELECT vertically (DOWN) instead of horizontally  
**       The query can be as complex as necessary with as many joins however the column names
**       must be unique because of the temp table.  Note image and text fields display only 
**       their size (DATALENGTH)
**
** PARM: @Help = 1 will display syntax and instructions
**
** RETR: the resultset of the records.  Notes displaying a lot of records will take a LONG time.  Generally
**       this should be used for recordsets of no more than 10.  
**
** AUTH: D. Simmons
**
** SYNTAX  sp_showdown 1 -- displays full syntax on how to run
**
** MOD DATE:
** 05.22.07 - DTS Prevent casting of image & text to varchar
** 05.20.07 - DTS original version
*********************************************************************************************************/
ALTER PROCEDURE [dbo].[sp_ShowDown] (
    @help   BIT = NULL
)
AS

SET NOCOUNT ON

    -- ------------------------------------------------------------------------
    -- DECLARATION AND TABLE CREATION
    -- ------------------------------------------------------------------------

    DECLARE 
        @Column     VARCHAR(60),        -- the fieldname
        @CurrOrdPos INT,                -- the order of the column in the table
        @SQL        VARCHAR(1000),      -- dynamic select statement
        @SQ         CHAR(1),            -- single quote
        @MaxTable   VARCHAR(1000),      -- holds the tempwide2 name - the true one stored in tempdb
        @RecordID   INT,                -- each record's number to aid in sorting when more than one record is return
        @DataType   VARCHAR(25),        -- the datatype of the field
        @FieldName  VARCHAR(200)            -- will hold column's name with brackets ready for the SELECT               

    IF OBJECT_ID('tempdb..#tempdown') IS NOT NULL DROP TABLE #tempdown

    CREATE TABLE #tempdown (
        Rec         INT,                -- short column names on purpose so it doesn't take up much 
        Ord         INT,                -- space in final result
        ColumnName  VARCHAR(60),        -- the columnname 
        Data        VARCHAR(7500)       -- the data for the column
    )

    -- ------------------------------------------------------------------------
    -- INITIALIZE
    -- ------------------------------------------------------------------------

    SET @RecordID = 0

    -- CONSTANTS
    SET @SQ = CHAR(39)      -- single quote


    -- ------------------------------------------------------------------------
    -- LOGIC
    -- ------------------------------------------------------------------------ 

    -- print the syntax and usage instructions to the result window
    IF @Help = 1 BEGIN
        PRINT 'Keep in mind that with temp tables the column names must be unique!'
        PRINT ' '
        PRINT 'Example of syntax: '
        PRINT ' '
        PRINT 'IF OBJECT_ID(''tempdb..#tempwide'') IS NOT NULL DROP TABLE #tempwide  -- ADD TO TOP OF YOUR SELECT'
        PRINT ' '
        PRINT 'SELECT TOP 1 * '
        PRINT 'INTO #tempwide           -- ADD THIS TO YOUR QUERY'
        PRINT 'FROM authors a'
        PRINT ' ' 
        PRINT 'EXEC _SHOWDOWN               -- ADD AS THE LAST LINE'
        PRINT '  '                         
        PRINT 'COPY THESE LINES and place where instructed'
        PRINT 'IF OBJECT_ID(''tempdb..#tempwide'') IS NOT NULL DROP TABLE #tempwide'
        PRINT 'INTO #tempwide'
        PRINT 'EXEC sp_SHOWDOWN'

        RETURN
    END

    -- Create a new 'wide' table so we can add a RecordID (DIDROCER) which allows muliple records and their fields 
    -- to be grouped together.  DIDROCER is RecordID backwards.  Needed a field name that will have an unlikely
    -- chance of ever being in a real table since it will be excluded from the results displayed vertically.
    SELECT  0 'DIDROCER', *
    INTO    #tempwide2
    FROM    #tempwide

    -- increment the record id for the table
    UPDATE  #tempwide2 SET  @RecordID = DIDROCER = @RecordID + 1

    -- get name of tempwide2 table (the true name in tempdb)
    SET @MaxTable = (   SELECT  MAX(TABLE_NAME) 
                        FROM    tempdb.INFORMATION_SCHEMA.TABLES
                        WHERE   Table_Name LIKE '%#tempwide2%'
                    )

    -- get the min ord position for the first column for my temp table.  Eliminates need for cursor
    SET @CurrOrdPos = ( SELECT  MIN(Ordinal_Position) 
                        FROM    tempdb.INFORMATION_SCHEMA.COLUMNS 
                        WHERE   Table_Name LIKE '%' + @MaxTable + '%' )


    -- while we have columns in the temp table loop through them and put their data into the 
    -- tempdown table
    WHILE @CurrOrdPos IS NOT NULL BEGIN 

        -- get a column name and the data type
        SELECT  @Column = COLUMN_NAME, @DataType = Data_Type
        FROM    tempdb.INFORMATION_SCHEMA.COLUMNS 
        WHERE   Table_Name LIKE '%' + @MaxTable + '%' 
        AND     Ordinal_Position = @CurrOrdPos 


        IF @Column <> 'DIDROCER' BEGIN      -- if it is not the recordid (spelled backward) row from tempwide2 get the row


            IF @DataType IN ( 'image', 'text' ) BEGIN
                -- 'Size of Data: ' + CONVERT(VARCHAR(15), DATALENGTH([NoteText] )) 
                SET @FieldName = @SQ + 'Size of Data: ' + @SQ + ' + CONVERT(VARCHAR(15), DATALENGTH(' + @FieldName + ')) '
            END ELSE BEGIN
                SET @FieldName = 'CAST( [' + @Column + '] AS VARCHAR(7500) )'           -- the fieldname w/ brackets used in SELECT to display the data
            END

            -- build the insert that will put the data into the tempdown table
            SET @SQL = ' INSERT INTO #tempdown ' 
            SET @SQL = @SQL + 'SELECT didrocer ' + @SQ + 'RecordID' + @SQ + ', '        -- recordid field from tempwide2 table
            SET @SQL = @SQL + CONVERT(VARCHAR(10), @CurrOrdPos) + ', '                  -- order of the column
            SET @SQL = @SQL + @SQ + @Column + @SQ + ' ' + @SQ + 'Field' + @SQ + ', '    -- field name 
            SET @SQL = @SQL + @FieldName + @SQ + @Column + @SQ                          -- field data
            SET @SQL = @SQL + ' FROM ' + @MaxTable                                      -- from tempwide2
        END

        --@SQL above looks like this:
        --INSERT INTO #tempdown SELECT DIDROCER 'RecordID', 5, 'UserID' 'Field', [UserID] 'UserID' FROM #tempwide2 {shorten}_____00010000003F
        --PRINT @SQL

        EXEC ( @SQL )       -- run the insert into #tempdown

        -- get the next column pos
        SET @CurrOrdPos = ( SELECT  MIN(Ordinal_Position) 
                            FROM    tempdb.INFORMATION_SCHEMA.COLUMNS 
                            WHERE   Table_Name LIKE '%' + @MaxTable + '%'
                                AND Ordinal_Position > @CurrOrdPos)


    END

    -- display the results VERTICALLY!
    SELECT  ColumnName, Data FROM   #tempdown ORDER BY Rec, Ord, ColumnName

    -- clean up
    IF OBJECT_ID('tempdb..#tempdown') IS NOT NULL DROP TABLE #tempdown
    IF OBJECT_ID('tempdb..#tempwide') IS NOT NULL DROP TABLE #tempwide
    IF OBJECT_ID('tempdb..#tempwide2') IS NOT NULL DROP TABLE #tempwide2

Thiết lập giường dữ liệu

--Setup testbed of data
DROP TABLE IF EXISTS dbo.customer
CREATE TABLE [dbo].[Customer] (
    [CustomerID] [int] NULL
    ,[Name] [varchar](30) NULL
    ,[RecordCreated] [datetime] NULL
    ,[RecordUpdated] [datetime] NULL
    ,
    ) ON [PRIMARY]
GO

INSERT [dbo].[Customer] ([CustomerID], [Name], [RecordCreated], [RecordUpdated]) VALUES (1, N'James', CAST(N'2017-11-01T16:16:21.297' AS DateTime), CAST(N'2017-11-01T16:52:02.427' AS DateTime))
GO
INSERT [dbo].[Customer] ([CustomerID], [Name], [RecordCreated], [RecordUpdated]) VALUES (2, N'John', CAST(N'2017-11-01T16:41:52.347' AS DateTime), CAST(N'2017-11-01T16:41:52.347' AS DateTime))
GO
INSERT [dbo].[Customer] ([CustomerID], [Name], [RecordCreated], [RecordUpdated]) VALUES (3, N'Sam', CAST(N'2017-11-01T16:50:25.430' AS DateTime), CAST(N'2017-11-01T16:50:25.430' AS DateTime))
GO
INSERT [dbo].[Customer] ([CustomerID], [Name], [RecordCreated], [RecordUpdated]) VALUES (1, N'James', CAST(N'2017-11-01T16:16:21.297' AS DateTime), CAST(N'2017-11-01T16:52:02.427' AS DateTime))
GO
INSERT [dbo].[Customer] ([CustomerID], [Name], [RecordCreated], [RecordUpdated]) VALUES (2, N'John', CAST(N'2017-11-01T16:41:52.347' AS DateTime), CAST(N'2017-11-01T16:41:52.347' AS DateTime))
GO
INSERT [dbo].[Customer] ([CustomerID], [Name], [RecordCreated], [RecordUpdated]) VALUES (3, N'Sam', CAST(N'2017-11-01T16:50:25.430' AS DateTime), CAST(N'2017-11-01T16:50:25.430' AS DateTime))
GO

Đây là quá trình thực tế để trả về kết quả ở định dạng dọc

IF OBJECT_ID('tempdb..#tempwide') IS NOT NULL DROP TABLE #tempwide

SELECT *
INTO #tempwide -- ADD THIS TO YOUR QUERY
FROM customer a

EXEC sp_SHOWDOWN -- ADD AS THE LAST LINE

Đây là kết quả

| CustomerID    | 1                   |
|---------------|---------------------|
| Name          | James               |
| RecordCreated | Nov  1 2017  4:16PM |
| RecordUpdated | Nov  1 2017  4:52PM |
| CustomerID    | 2                   |
| Name          | John                |
| RecordCreated | Nov  1 2017  4:41PM |
| RecordUpdated | Nov  1 2017  4:41PM |
| CustomerID    | 3                   |
| Name          | Sam                 |
| RecordCreated | Nov  1 2017  4:50PM |
| RecordUpdated | Nov  1 2017  4:50PM |
| CustomerID    | 1                   |
| Name          | James               |
| RecordCreated | Nov  1 2017  4:16PM |
| RecordUpdated | Nov  1 2017  4:52PM |
| CustomerID    | 2                   |
| Name          | John                |
| RecordCreated | Nov  1 2017  4:41PM |
| RecordUpdated | Nov  1 2017  4:41PM |
| CustomerID    | 3                   |
| Name          | Sam                 |
| RecordCreated | Nov  1 2017  4:50PM |
| RecordUpdated | Nov  1 2017  4:50PM |

Cập nhật (2018-02-09)

Sau khi đăng câu trả lời của tôi, Martin Smith đã thêm một bình luận tham chiếu một cách tiếp cận cực kỳ đơn giản cho vấn đề này bằng cách sử dụng FOR XML PATHvà một vài trong số CROSS APPLYđó.

Tôi bao gồm giải pháp của anh ấy ở đây trong trường hợp liên kết SQL Fiddle bị chết.

SELECT n.value('local-name(.)', 'SYSNAME') AS Col,
       n.value('.', 'nvarchar(4000)')
FROM Customer c
CROSS APPLY 
(SELECT c.*
 FOR XML PATH('r'), TYPE) ca(x)
 CROSS APPLY ca.x.nodes('/r/*') n(n)

1
Chắc chắn sẽ có những cách đơn giản hơn để thực hiện Proc đó. Ví dụ: sqlfiddle.com/#!18/8f0a9/10/0 (mặc dù hiện tại nó không xử lý việc đặt hàng hoặc tất cả các kiểu dữ liệu nhưng hiển thị ý tưởng)
Martin Smith


2

Nếu bạn đang xử lý các trường không varchar/nvarcharvà vẫn muốn sự đơn giản [Field] + char(13), bạn có thể bỏ qua phần CONVERT/CASTsoạn sẵn bằng cách sử dụng CONCAT(SQL v2012 +), để xử lý bất cứ điều gì bạn ném vào nó

https://docs.microsoft.com/en-us/sql/t-sql/fifts/concat-transact-sql


SELECT CONCAT(1, char(13), GETDATE(), char(13), 3.0, char(13), 'A')
-------------------------------------------
1
Feb  9 2018 11:39AM
3.0
A

(1 row affected)

* CONCATđược giới hạn ở 254 tham số

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.