使用UNION从两个表获取数据时,存储过程会引发错误

时间:2018-01-04 06:50:34

标签: sql sql-server

我有两个表格,在这个截图中显示:

see image here

我正在编写一个存储过程,它将从两个表中返回数据:

ALTER PROCEDURE [dbo].[GetInventoryDetails] 
    @MaterialId INT
AS
BEGIN
    SELECT 
        tms.Material_ID AS MaterialId,
        tmm.Name As MaterialName,
        CONVERT(varchar,Quantity) AS AddedQuantity, 
        UtilizedQuantity ='-',
        tcl.LedgerName AS SupplierName,
        UsedFor = '-',
        tmm.CurrentStock,
        tmm.OpeningStock,
        CONVERT(DATETIME,CONVERT(VARCHAR(100), tms.Material_Date, 112)) AS MaterialDate,
        tms.Narration AS Narration
    FROM 
        tblMaterialSheet tms 
    JOIN 
        tblMaterialMaster tmm ON tmm.Material_ID = tms.Material_ID
    JOIN  
        tblCompanyLedger tcl ON tcl.Pk_LedgerId = tms.Ledger_ID
    WHERE 
        tms.Material_ID = @MaterialId 
        AND tms.isActive = 1

UNION 

SELECT 
    tmu.Material_ID AS MaterialId,
    tmm.Name As MaterialName,
    AddedQuantity = '-',
    CONVERT(varchar,Utilized_Quantity) AS UtilizedQuantity,
    CONVERT(DATETIME,CONVERT(VARCHAR(100), Utilization_Date, 112)) AS MaterialDate,
    SupplierName = '-',
    tbst.Name AS UsedFor,
    tmm.CurrentStock,
    tmm.OpeningStock,
    tmu.Narration As Narration
FROM 
    tblMaterialUtilization tmu 
JOIN 
    tblMaterialMaster tmm ON tmm.Material_ID = tmu.Material_ID
JOIN 
    tblBuildingSubTask tbst ON tbst.BuildingSubTask_ID = tmu.BuildingSubTask_ID
WHERE 
    tmu.Material_ID = @MaterialId
    AND tmu.isActive = 1
END 

当我调用存储过程时,它会抛出一个错误:

  

从字符串转换日期和/或时间时转换失败。

表格结构:tblmaterialsheet

CREATE TABLE [dbo].[tblMaterialSheet]
(
    [MaterialSheet_ID] [int] IDENTITY(1,1) NOT NULL,
    [Company_ID] [int] NOT NULL,
    [User_ID] [int] NOT NULL,
    [BuildingSubTask_ID] [int] NOT NULL,
    [Material_Date] [datetime] NOT NULL,
    [Material_ID] [int] NOT NULL,
    [Unit_ID] [int] NOT NULL,
    [Quantity] [decimal](10, 2) NOT NULL,
    [Size_ID] [int] NULL,
    [Height] [decimal](6, 2) NULL,
    [Width] [decimal](6, 2) NULL,
    [Rate_Per_Unit] [money] NULL,
    [Paid_Amount] [money] NULL,
    [Total_Amount] [money] NULL,
    [Vehical_No] [varchar](50) NULL,
    [Ledger_ID] [int] NULL,
    [Narration] [varchar](max) NULL,
    [Challan_No] [int] NULL,
    [Bill_ID] [int] NULL,
    [isBilled] [bit] NOT NULL,
    [Approval] [varchar](50) NULL,
    [Approval_ModifiedDate] [datetime] NULL,
    [UploadImage] [image] NULL,
    [isActive] [bit] NOT NULL,
    [CreatedBy] [int] NOT NULL,
    [CreatedDate] [datetime] NOT NULL,
    [ModifiedBy] [int] NULL,
    [ModifiedDate] [datetime] NULL
)

表格结构:tblMaterialUtilization

CREATE TABLE [dbo].[tblMaterialUtilization]
(
    [MaterialUtilization_ID] [int] IDENTITY(1,1) NOT NULL,
    [Company_ID] [int] NOT NULL,
    [User_ID] [int] NOT NULL,
    [BuildingSubTask_ID] [int] NOT NULL,
    [Material_ID] [int] NOT NULL,
    [Utilization_Date] [datetime] NOT NULL,
    [Utilized_Quantity] [decimal](10, 2) NOT NULL,
    [Narration] [varchar](max) NOT NULL,
    [IsActive] [bit] NOT NULL,
    [CreatedBy] [int] NOT NULL,
    [CreatedDate] [datetime] NOT NULL,
    [ModifiedBy] [int] NULL,
    [ModifiedDate] [datetime] NULL
)

表格结构:tblMaterialMaster

CREATE TABLE [dbo].[tblMaterialMaster]
(
    [Material_ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](100) NOT NULL,
    [Unit_ID] [int] NOT NULL,
    [IsActive] [bit] NOT NULL,
    [CreatedBy] [int] NOT NULL,
    [CreatedDate] [datetime] NOT NULL,
    [ModifiedBy] [int] NULL,
    [ModifiedDate] [datetime] NULL,
    [OpeningStock] [numeric](18, 0) NULL,
    [PurchaseLedger] [numeric](18, 0) NULL,
    [CurrentStock] [numeric](18, 0) NULL
)

表格结构:tblBuildingSubTask

CREATE TABLE [dbo].[tblBuildingSubTask]
(
    [BuildingSubTask_ID] [int] IDENTITY(1,1) NOT NULL,
    [BuildingTask_ID] [int] NOT NULL,
    [Name] [varchar](200) NOT NULL,
    [Narration] [varchar](max) NULL,
    [StartDate] [datetime] NULL,
    [TargetCompletionDate] [datetime] NULL,
    [ActualCompletionDate] [datetime] NULL,
    [IsActive] [bit] NOT NULL,
    [CreatedBy] [int] NOT NULL,
    [CreatedDate] [datetime] NOT NULL,
    [ModifiedBy] [int] NULL,
    [ModifiedDate] [datetime] NULL
)

如何解决此错误?

3 个答案:

答案 0 :(得分:3)

立即尝试:列的顺序不是相同的顺序,因此它获取了同一列的不同数据类型值。数据类型和顺序在UNION中最重要

ALTER PROCEDURE [dbo].[GetInventoryDetails] 
@MaterialId int
AS
BEGIN
    SELECT 
    tms.Material_ID AS MaterialId,
    tmm.Name As MaterialName,
    CONVERT(varchar,Quantity) AS AddedQuantity, 
    UtilizedQuantity ='-',
    tcl.LedgerName AS SupplierName,
    UsedFor='-',
    tmm.CurrentStock,
    tmm.OpeningStock,
    CONVERT(DATETIME,CONVERT(VARCHAR(100), tms.Material_Date, 112)) AS MaterialDate,
    tms.Narration As Narration
        FROM 
            tblMaterialSheet tms 
            JOIN tblMaterialMaster tmm on tmm.Material_ID = tms.Material_ID
            JOIN tblCompanyLedger tcl on tcl.Pk_LedgerId = tms.Ledger_ID
        WHERE 
            tms.Material_ID = @MaterialId 
        AND 
            tms.isActive = 1
UNION 
    SELECT 
    tmu.Material_ID AS MaterialId,
    tmm.Name As MaterialName,
    AddedQuantity = '-',
    CONVERT(varchar,Utilized_Quantity) AS UtilizedQuantity,
    SupplierName = '-', --Moved up
    tbst.Name AS UsedFor, --Moved up
    tmm.CurrentStock, --Moved up
    tmm.OpeningStock, --Moved up
    CONVERT(DATETIME,CONVERT(VARCHAR(100), Utilization_Date, 112)) AS MaterialDate,
    tmu.Narration As Narration
        FROM 
            tblMaterialUtilization tmu 
            JOIN tblMaterialMaster tmm on tmm.Material_ID = tmu.Material_ID
            JOIN tblBuildingSubTask tbst on tbst.BuildingSubTask_ID = tmu.BuildingSubTask_ID
        WHERE 
            tmu.Material_ID = @MaterialId
        AND 
            tmu.isActive = 1
END 

答案 1 :(得分:2)

我采取的问题排查方向:

看看你的SQL。您正在寻找可能将非日期类型转换为日期类型的任何内容。您的错误可能意味着您将某个地方的数据转换为无法转换的日期。请注意,这可能包括输出日期的比较或函数。

查看您的示例,在不知道实际数据类型的情况下,我唯一可以看到这种情况的地方是tms.Material_Date和Utilization_Date上的显式CONVERT函数。我快速评论这些并分别运行UNION的每一半。如果它们有效,我可以取消注释一个或另一个,直到我找出导致错误的字段。如果他们独立工作但没有工会,我知道将工会后的字段转换为日期,因为工会前字段是日期。

在联盟前的上半场说出来。我跑了:

SELECT * As Narration
    FROM 
        tblMaterialSheet tms 
        JOIN tblMaterialMaster tmm on tmm.Material_ID = tms.Material_ID
        JOIN tblCompanyLedger tcl on tcl.Pk_LedgerId = tms.Ledger_ID
    WHERE 
        tms.Material_ID = @MaterialId 
    AND 
        tms.isActive = 1
    AND
        ISDATE(tms.Material_Date) = 0

您可能需要在转换过程中向外工作以查看其转换的位置,例如,         和             ISDATE(CONVERT(VARCHAR(100),tms.Material_Date,112))

然后你应该对这个问题有个好主意。

顺便提及,

CONVERT(DATETIME,CONVERT(VARCHAR(100),Utilization_Date,112))

看起来很奇怪 - 您想通过将日期转换为varchar并返回来实现这一目标吗?

答案 2 :(得分:1)

当您编写UNION或UNION ALL时,您应该确保以下内容

  1. 每个选择的列数应该相同
  2. 每个选择的相同位置的列的数据类型应该相同
  3. 假设我有第一个选择的字符数据类型的列,并且我试图将它与DateTime数据类型结合,那么我将得到错误

    SELECT 'ABCD'
    UNION ALL
    SELECT GETDATE()
    

    这将抛出错误

      

    Msg 241,Level 16,State 1,Line 1
      从字符串转换日期和/或时间时转换失败。

    因为数据类型不匹配。

    这会导致另一个错误:

    SELECT 'ABCD',GETDATE()
    UNION ALL
    SELECT GETDATE()
    

    像这样:

      

    Msg 205,Level 16,State 1,Line 1
      使用UNION,INTERSECT或EXCEPT运算符组合的所有查询在目标列表中必须具有相同数量的表达式。

    因为列数不匹配。

    因此,请确保UNION中每个列的数据类型匹配,如果它们不匹配,请尝试转换或转换