如何选择列名并为 SQL Server 获取数据?

Posted

技术标签:

【中文标题】如何选择列名并为 SQL Server 获取数据?【英文标题】:How do you select Column Names and grab the data for SQL Server? 【发布时间】:2017-03-14 18:35:27 【问题描述】:

我想寻求帮助以获取 SELECT 语句,以帮助我解决当前的困境。我正在使用 SQL Server 在 vb.net 中创建一个新项目,我的雇主希望我创建的报告之一是使用他们给我的 excel 文件中的数据获取所需的零件名称和数量,但是,它的工作方式类似于这个:

数据实际上比这个大很多(比如 200 多个部分),但这是一般的想法。我将在其中输入 DWG 名称,并且我想要一个具有如下输出的 SELECT:

(如果用户使用 DWG1:)

DWG1     1    Part3  
DWG1     2    Part4
DWG1     1    Part5

有没有办法只获取其中数字大于 0 的列名,得到确切的数字是什么,然后是那个列名?我认为给我 Excel 文件的人没有考虑到正确的表格结构。

【问题讨论】:

您使用的是哪个 DBMS? mysql sql 服务器。你能试着清楚地解释你想要完成的事情吗?从您发布的图片来看,这对我来说毫无意义。 这看起来你可能想使用 UNPIVOT 但很难理解你真正想要的。 对不起,SQL Server。该站点只是将其自动踢到了 mysql。基本上,给定一行开头的值,我想遍历整行并选择任何大于 0 的值。如果这些值大于 0,我需要获取它们所在的列名。 一次只针对 1 个 DWG,还是全部? 请一次 1 个 DWG。 【参考方案1】:

UNPIVOT 会更高效,但如果您想要指定 200 个字段,请考虑以下几点:

Declare @YourTable table (DWG varchar(25),Part1 int,Part2 int,Part3 int,Part4 int,Part5 int)
Insert into @YourTable values
('DWG1',0,0,1,2,1),
('DWG2',0,0,0,0,1)

Select C.*
  From @YourTable A
  Cross Apply (Select XMLData=cast((Select A.* for XML RAW) as xml)) B
  Cross Apply (
                Select DWG   = r.value('@DWG','varchar(25)')              --<< case sensitive
                      ,Item  = attr.value('local-name(.)','varchar(100)')
                      ,Value = attr.value('.','varchar(max)')             --<< can be int if desired
                 From  B.XMLData.nodes('/row') as A(r)
                 Cross Apply A.r.nodes('./@*') as B(attr)
                 Where attr.value('local-name(.)','varchar(100)') not in ('DWG','OtherFieldsToExclude')
              ) C
  --Where A.DWG='DWG1'

退货

DWG     Item    Value
DWG1    Part1   0
DWG1    Part2   0
DWG1    Part3   1
DWG1    Part4   2
DWG1    Part5   1
DWG2    Part1   0
DWG2    Part2   0
DWG2    Part3   0
DWG2    Part4   0
DWG2    Part5   1

【讨论】:

@C.Clements 很高兴它有帮助,我相信你会看到性能是可观的。 :) @C.Clements 为了记录,它被称为 EAV 结构(实体属性值)。在处理广泛和/或变化的表格时非常有帮助【参考方案2】:

从包含此数据的电子表格开始:

我使用了一个小程序从电子表格文件中读取数据并按照您显示的方式输出数据:

Option Infer On
Option Strict On

Imports System.Data.OleDb

Module Module1

    Class Part
        Property Name As String
        Property Quantity As Decimal

        Public Overrides Function ToString() As String
            Return $"Name: Quantity"
        End Function

    End Class

    Class Dwg
        Property Name As String
        Property Parts As List(Of Part)

        Public Overrides Function ToString() As String
            Return $"Name - String.Join(", ", Parts)"
        End Function

    End Class

    Sub Main()
        Dim xlFile = "C:\temp\PartsList.xlsx"
        Dim connStr = $"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=xlFile;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"

        Dim dt As New DataTable

        Using conn = New OleDbConnection(connStr)
            Dim qry = "SELECT * FROM [Sheet1$]"
            Using da = New OleDbDataAdapter(qry, conn)
                da.Fill(dt)
            End Using
        End Using

        ' To show the column names...
        'For Each col As DataColumn In dt.Columns
        '   Console.WriteLine(col.ColumnName)
        'Next

        Dim dwgs As New List(Of Dwg)

        ' Read the data into a list... '
        For i = 0 To dt.Rows.Count - 1
            Dim dx As New Dwg With .Name = CStr(dt.Rows(i)(0))
            Dim parts As New List(Of Part)
            For j = 1 To dt.Columns.Count - 1
                Dim qty = CDec(dt.Rows(i)(j))
                If qty <> 0 Then
                    parts.Add(New Part With .Name = dt.Columns(j).ColumnName, .Quantity = qty)
                End If
            Next
            dx.Parts = parts
            dwgs.Add(dx)
        Next

        ' Show all the data read... '
        Console.WriteLine("ALL DWGS:-")
        For Each d As Dwg In dwgs
            Console.WriteLine(d.ToString())
        Next
        Console.WriteLine()

        ' Show the data from a selected item... '
        Dim selectedDwg = "DWG1"

        Console.WriteLine($"Drawing selectedDwg:-")
        Dim dw = dwgs.First(Function(x) x.Name = selectedDwg)

        If dw IsNot Nothing Then
            For Each p In dw.Parts
                Console.WriteLine($"dw.Name,-10p.Quantity,-8p.Name,-12")
            Next
        End If

        Console.ReadLine()

    End Sub

End Module

输出:

ALL DWGS:-
DWG1 - Sprocket: 1, Widget: 2, Part 5: 1
DWG2 - Part 5: 1
DWG3 - Part 1: 1, Sprocket: 2, Widget: 1

Drawing DWG1:-
DWG1      1       Sprocket
DWG1      2       Widget
DWG1      1       Part 5

在程序中获得数据后,很容易将其插入到具有适当架构的数据库中,例如 SQL Server。

[我没有使用 Excel 创建电子表格 - 我使用 LibreOffice Calc 并将其保存为 xlsx 文件,并且我必须在连接字符串中为 Provider 安装 Microsoft Access Database Engine 2010 Redistributable。]

【讨论】:

以上是关于如何选择列名并为 SQL Server 获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何在sql server中获取更新的列名

SQL - 如何从多个可能的列名中进行选择?

sql server修改列名语句

SQL Server 4

SQL Server 错误无效的列名“NaN”

为sql server服务提供的指定凭据无效 怎么弄啊