Convert Access Crosstab Query to SQL Server - sql-server

I have a crosstab query in MS Access which runs very slow after migrating my backend to an SQL Server 2017. So I want to create a view in SQL that does the same aggregation.
MS Access Query:
TRANSFORM Sum([Auftrag Positionen].Gesamtpreis) AS SummevonGesamtpreis
SELECT Format$([Stammdaten Datum].[Datum],'yyyy\/mm mmmm') AS Monat, Sum([Auftrag Positionen].Gesamtpreis) AS Gesamt
FROM [Stammdaten Datum] LEFT JOIN (Auftrag LEFT JOIN ([Stammdaten Statistik] RIGHT JOIN [Auftrag Positionen] ON [Stammdaten Statistik].Kennzeichen = [Auftrag Positionen].Statistik) ON Auftrag.[Auftrags-Nummer] = [Auftrag Positionen].[Auftrags-Nummer]) ON [Stammdaten Datum].Datum = Auftrag.Auftragseingang
WHERE (((Auftrag.[Auftrag-Angebot])="Auftrag"))
GROUP BY Format$([Stammdaten Datum].[Datum],'yyyy\/mm mmmm')
ORDER BY Format$([Stammdaten Datum].[Datum],'yyyy\/mm mmmm') DESC
PIVOT [Stammdaten Statistik].Beschreibung;
I get that I can cancel out the access date formatting:
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, [Stammdaten Datum].[Datum]), 0) AS Monat, Sum([Auftrag Positionen].Gesamtpreis) AS Gesamt
FROM [ROBI_1].[dbo].[Stammdaten Datum] LEFT JOIN ([ROBI_1].[dbo].Auftrag LEFT JOIN (ROBI_1.dbo.[Stammdaten Statistik] RIGHT JOIN ROBI_1.dbo.[Auftrag Positionen] ON [Stammdaten Statistik].Kennzeichen = [Auftrag Positionen].Statistik) ON Auftrag.[Auftrags-Nummer] = [Auftrag Positionen].[Auftrags-Nummer]) ON [ROBI_1].[dbo].[Stammdaten Datum].Datum = Auftrag.Auftragseingang
WHERE ((([Auftrag].[Auftrag-Angebot])='Auftrag'))
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Stammdaten Datum].[Datum]), 0)
ORDER BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Stammdaten Datum].[Datum]), 0) DESC
But I don't know how to do the pivot aggregation, everything I've tried gave me syntax errors. (I am a noob in SQL/T-SQL indeed).
I appreciate any help!

I guess it would be something like this:
;WITH MonatGesamt AS
(
SELECT
Monat = DATEPART(MONTH, SD.Datum)
, Gesamtpreis = ISNULL(AP.Gesamtpreis, 0)
FROM ROBI_1.dbo.[Stammdaten Datum] SD
LEFT JOIN ROBI_1.dbo.Auftrag AT ON AT.Auftragseingang = SD.Datum
LEFT JOIN ROBI_1.dbo.[Auftrag Positionen] AP ON AP.[Auftrags-Nummer] = AT.[Auftrags-Nummer]
WHERE AT.[Auftrag-Angebot] = 'Auftrag'
)
SELECT
Monat
, Gesamt = SUM(Gesamtpreis)
FROM MonatGesamt
GROUP BY Monat
ORDER BY Monat DESC

Related

Similar to the last Joining two tables on columns that don't equal and summing 3 columns in the second table

I have a equipment table and a mobile work order table that I am wanting to join, I am wanting to display all the equipment and the reactive hours. If there is no reactive hours for a certain piece of equipment then I want to display a zero in the rows where value is null. This is what I have below. It only gives me the equipment that has reactive hours in the other table.
SQL Server
Select e.EquipNbr, coalesce(sum(mw.MaintTech1hours + mw.MaintTech2hours + mw.MaintTech3hours), 0) ReactiveHours
From MblEquip e
inner join MobileWorkOrder mw on
mw.EquipNbr = e.EquipNbr
and mw.DateTm between DATEADD(month, DATEDIFF(month, 0, getDate()), 0)
and DATEADD(month, DATEDIFF(month, -1, getDate()), -1)
where e.DelFlg = 0 and mw.Category = 'Reactive'
group by e.EquipNbr order by ReactiveHours Desc;
If you test a value into 'where condition', your 'left outer join' is equivalent to 'inner join'.
Try this (SQL remained)
Select e.EquipNbr, coalesce(sum(isnull(mw.MaintTech1hours, 0) + isnull(mw.MaintTech2hours, 0) + isnull(mw.MaintTech3hours, 0)), 0) ReactiveHours
From MblEquip e
left outer join MobileWorkOrder mw on mw.EquipNbr = e.EquipNbr and mw.Category = 'Reactive'
and Year(mw.DateTm) =Year(getdate()) and Month(mw.DateTm) =Month(getdate())
where e.DelFlg = 0
group by e.EquipNbr
order by ReactiveHours Desc;

I'm having error deriving records using Case When Statement between two specific months using Month(EndofMonth) = 08 and Month (EndOfMonth) = 09?

I need to derive the records between two specific dates.
I'm having error in the "Case When" statement.
SELECT T1.BR,T1.CID
SUM(ISNULL(CASE WHEN TRNDATE BETWEEN DATEDIFF(dd, 1,(EOMDATE IN MONTH(EOMDATE)=08)) AND (EOMDATE IN MONTH(EOMDATE)=09) THEN TransactionAmount end, 0)) AS SHRAWAN
FROM
--Nesting
(SELECT TRH.BR, TRH.CID, TRH.TRNDATE, SUM(TRH.TRNAMT) AS TransactionAmount FROM T_TRNHIST TRH
LEFT JOIN T_GLLINK GLL ON GLL.BR = TRH.BR AND TRH.GLCode = GLL.Code AND GLL.CoopRep01 = 'Y' AND GLL.TableID IN ('10','30') AND TRH.AppType+'0' = GLL.TableID
LEFT JOIN T_GLCONTROL GLC ON GLC.BR = TRH.BR
LEFT JOIN T_CALENDAR C ON TRH.BR = C.BR
WHERE GLC.FINYEAR = '2018' /*#Finyear*/ AND TRH.TRNDATE BETWEEN /*#FromDate*/GLC.FinYrStartDate And GLC.FinyrEndDate/*#ToDate*/ AND TRH.APPTYPE IN ('1','3')
AND (TRH.TRNTYPE BETWEEN '101' AND '159' OR TRH.TrnType BETWEEN '301' AND '359') AND TRH.TrnType%2=1 AND TRH.TrnAmt>0
GROUP BY TRH.BR, TRH.CID, TRH.TrnDate) T1 --, T_CALENDAR C, T_GLCONTROL G
WHERE T1.CID = '000003'
GROUP BY T1.BR, T1.CID
ORDER BY T1.BR, T1.CID
The expected result would be sum of all the amounts deposited between the given parameter dates.
TRNDATE BETWEEN DATEDIFF(dd, 1,(EOMDATE IN MONTH(EOMDATE)=08)) AND (EOMDATE IN MONTH(EOMDATE)=09)

Linq results different than the sql result

I am having an MVC4 web application where I am using LINQ.
I have the below query which results 53 rows in SQL.
select * from table1 t join
[table2] tpf on t.TestID=tpf.TestID
join
table3 pf on tpf.Test2ID =pf.Test2ID
join table4 pfp on
pf.Test3ID = pfp.Test3ID
join table5 p on pfp.Test5ID = p.Test5ID where t.testtypeid=1
order by pfp.Test3ID,pf.Test2ID
If I convert the same query as below it returns more records.
trvm.MyTestVMs = (
from tt in db.table1s
join ttpf in db.table2s on tt.TestID equals ttpf.TestID
join pf in db.table3s on ttpf.Test2ID equals pf.Test2ID
join pfp in db.table4s on pf.Test3ID equals pfp.Test3ID
join p in table5s on pfp.Test5ID equals p.Test5ID
where tt.testtypeid == 1
orderby pfp.Test3ID
orderby pf.Test2ID
select new MyTestVM
{
FamilyID = pf.Test2ID,
ProductID = p.Test3ID,
Desc = p.Description
}
).ToList();
The result which is getting from SQL and the above LINQ varies. Actually, there are some duplicate result I am getting from the LINQ query. What is causing this difference?
It turns out that the LINQ query is not equivalent to the SQL query posted due to the usage of a products query variable (not shown in the post) which causes one of the many-to-many link table to be included twice, thus producing more records.
One way to fix the problem is to replace products with db.Products and apply the same filters as in the query variables you were trying to reuse.
But if you want to reuse query variables, then here is the correct way to do that:
// Eliminate the need of DbFunctions.TruncateTime(dt) inside the queries
dt = dt.Date;
// Queries
var productFamilys = (
from tt in db.TestTypes
join ttpf in db.TestTypeProductFamilys on tt.TestTypeID equals ttpf.TestTypeID
join pf in db.ProductFamilys on ttpf.ProductFamilyID equals pf.ProductFamilyID
where tt.TestTypeID == TestTypeID
where DbFunctions.TruncateTime(pf.StartDate) <= dt
where DbFunctions.TruncateTime(pf.EndDate) > dt
select pf
);
var productFamilyProducts = (
from pf in productFamilys
join pfp in db.ProductFamilyProducts on pf.ProductFamilyID equals pfp.ProductFamilyID
join p in db.Products on pfp.ProductID equals p.ProductID
where DbFunctions.TruncateTime(p.StartDate) <= dt
where DbFunctions.TruncateTime(p.EndDate) > dt
select new { Family = pf, Product = p }
);
var products = (
from pfp in productFamilyProducts
select pfp.Product
);
var productFamilyProductVMs = (
from pfp in productFamilyProducts
orderby pfp.Product.ProductID, pfp.Family.ProductFamilyID
select new ProductFamilyProductVM
{
ProductFamilyID = pfp.Family.ProductFamilyID,
ProductID = pfp.Product.ProductID,
ProdDesc = pfp.Product.Description
}
);
// Results
trvm.ProductFamilys = productFamilys.ToList();
trvm.Products = products.ToList();
trvm.ProductFamilyProductVMs = productFamilyProductVMs.ToList();
Now the SQL for the last query (the one in question) looks like this
SELECT
[Project1].[ProductFamilyID] AS [ProductFamilyID],
[Project1].[ProductID] AS [ProductID],
[Project1].[Description] AS [Description]
FROM ( SELECT
[Extent2].[ProductFamilyID] AS [ProductFamilyID],
[Extent4].[ProductID] AS [ProductID],
[Extent4].[Description] AS [Description]
FROM [dbo].[TestTypeProductFamilies] AS [Extent1]
INNER JOIN [dbo].[ProductFamilies] AS [Extent2] ON [Extent1].[ProductFamilyID] = [Extent2].[ProductFamilyID]
INNER JOIN [dbo].[ProductFamilyProducts] AS [Extent3] ON [Extent2].[ProductFamilyID] = [Extent3].[ProductFamilyID]
INNER JOIN [dbo].[Products] AS [Extent4] ON [Extent3].[ProductID] = [Extent4].[ProductID]
WHERE ([Extent1].[TestTypeID] = #p__linq__0) AND ((convert (datetime2, convert(varchar(255), [Extent2].[StartDate], 102) , 102)) <= #p__linq__1) AND ((convert (datetime2, convert(varchar(255), [Extent2].[EndDate], 102) , 102)) > #p__linq__2) AND ((convert (datetime2, convert(varchar(255), [Extent4].[StartDate], 102) , 102)) <= #p__linq__3) AND ((convert (datetime2, convert(varchar(255), [Extent4].[EndDate], 102) , 102)) > #p__linq__4)
) AS [Project1]
ORDER BY [Project1].[ProductID] ASC, [Project1].[ProductFamilyID] ASC
i.e. pretty similar to the sample SQL query and should produce the same results.
Result is different because in your second query , you have two "OrderBy" and because of that, the second OrderBy it's works over the collection which is result of first "OrderBy" and is reordering the items.
Change
orderby pfp.ProductID
orderby pf.ProductFamilyID
from your second query in
orderby pfp.ProductID, pf.ProductFamilyID
to get same results

how to use convert and datepart at the same time

I have here a select command which is used in my crystal report:
SELECT cfvgl.v_id, operator.o_id, cfvgl.cfvgl_no, operator.owner_name,
operator.business_address, vessel_details.ship_name, payment.or_number ,
payment .date_paid , payment.amount , signature.data,
cfvgl.cfvgl_date_released, DATEPART(day, cfvgl.cfvgl_validity_start) as day_issued,
DATEPART(month, cfvgl.cfvgl_validity_start) as month_issued,
DATEPART(year, cfvgl.cfvgl_validity_start) as year,
gear.bag_bunt_mesh_size, gear.body_mesh_size, gear.wing_mesh_size,
cfvgl.catcher_type, cfvgl.other_gear, gear.stretched_depth,
gear.finished_depth, gear.mesh_size, gear.finished_length,
gear.finished_width, gear.total_length, gear.cod_end_mesh_size,
gear.otter_board_size, gear.towing_rope_length, gear.tomweight,
gear.bouyline_length, gear.branchline_length, gear.branchline_distance,
gear.hook_number, gear.hook_type, gear.hook_size, gear.bait_type,
gear.hook_total_number, gear.target_species, gear.mainline_length,
gear.swivel_size, gear.wire_leader_length, gear.netting_type
FROM cfvgl INNER JOIN
vessel_details ON vessel_details.v_id = cfvgl.v_id INNER JOIN
operator ON vessel_details.o_id = operator.o_id LEFT OUTER JOIN
applications ON vessel_details.v_id = applications.v_id LEFT OUTER JOIN
payment ON payment.app_no = applications.app_no LEFT OUTER JOIN
gear ON gear.v_id = vessel_details.v_id LEFT OUTER JOIN
signature ON signature.signature_id = cfvgl.signature_id
my problem is , i have to convert and display the return date of the datepart(month) as words, for example 1 = january ..
i only datepart the month ,
DATEPART(month, cfvgl.cfvgl_validity_start) as month_issued
how will i able to change the format of the datepart month to words?
thanks.
Use DATENAME to get the name.
DATENAME(month, cfvgl.cfvgl_validity_start) as month_issued
Use the DATENAME function to get the month in words like so:
SELECT DATENAME(month, cfvgl.cfvgl_validity_start) AS month_issued
FROM yourtable

Work Around Divide By Zero Error in SQL SELECT

SELECT
*
FROM
RM_Sales_Union
WHERE
DOCDATE >= 'September 1, 2011'
AND DOCDATE < 'October 1, 2011'
AND CUSTNMBR = '2186020'
That query results in an error:
Msg 8134, Level 16, State 1, Line 1
Divide by zero error encountered.
if run as shown.
Excluding the last line AND CUSTNMBR = '2186020' allows the query to complete.
CUSTNMBR is a char(21) field. Divide by zero has me confused.
What is the "correct" way to work around this?
RM_Sales_Union is a union query view:
SELECT ACTNUMBR_1,
ACTNUMBR_2,
ACTNUMBR_3,
ORSLSAMT,
CUSTCLAS,
CUSTNAME,
CUSTNMBR,
SLPRSNID,
DOCABREV,
CSPORNBR,
CURNCYID,
DOCDATE,
DOCNUMBR,
GLPOSTDT,
SLSAMNT,
VOIDSTTS,
SLPRSNFN,
SPRSNSLN,
DocOrigin,
ORFRTAMT,
FRTAMNT,
COMPRCNT,
TRDISAMT,
ORTDISAM,
ORMISCAMT,
ORTAXAMT,
ORCTRXAM
FROM dbo.RM_Sales_Hist
UNION
SELECT ACTNUMBR_1,
ACTNUMBR_2,
ACTNUMBR_3,
ORSLSAMT,
CUSTCLAS,
CUSTNAME,
CUSTNMBR,
SLPRSNID,
DOCABREV,
CSPORNBR,
CURNCYID,
DOCDATE,
DOCNUMBR,
GLPOSTDT,
SLSAMNT,
VOIDSTTS,
SLPRSNFN,
SPRSNSLN,
DocOrigin,
ORFRTAMT,
FRTAMNT,
COMPRCNT,
TRDISAMT,
ORTDISAM,
ORMISCAMT,
ORTAXAMT,
ORCTRXAM
FROM dbo.RM_Sales_Open
RM_Sales_Hist and RM_Sales_Open are views defined as follows:
--RM_Sales_Hist
SELECT dbo.GL_Sales_Accounts.ACTNUMBR_1,
dbo.GL_Sales_Accounts.ACTNUMBR_2,
dbo.GL_Sales_Accounts.ACTNUMBR_3,
ISNULL(dbo.MC020102.ORSLSAMT, dbo.RM30101.SLSAMNT) AS ORSLSAMT,
dbo.RM00101.CUSTCLAS,
dbo.RM00101.CUSTNAME,
dbo.RM00101.CUSTNMBR,
dbo.RM00101.SLPRSNID,
dbo.RM40401.DOCABREV,
dbo.RM30101.CSPORNBR,
dbo.RM30101.CURNCYID,
dbo.RM30101.DOCDATE,
dbo.RM30101.DOCNUMBR,
dbo.RM30101.GLPOSTDT,
dbo.RM30101.SLSAMNT,
dbo.RM30101.VOIDSTTS,
dbo.RM00301.SLPRSNFN,
dbo.RM00301.SPRSNSLN,
'HIST' AS DocOrigin,
ISNULL(dbo.MC020102.ORFRTAMT, dbo.RM30101.FRTAMNT) AS ORFRTAMT,
dbo.RM30101.FRTAMNT,
dbo.RM00301.COMPRCNT,
dbo.RM30101.TRDISAMT,
ISNULL(dbo.MC020102.ORTDISAM, 0) AS ORTDISAM,
ISNULL(dbo.MC020102.ORMISCAMT, 0) AS ORMISCAMT,
ISNULL(dbo.MC020102.ORTAXAMT, 0) AS ORTAXAMT,
ISNULL(dbo.MC020102.ORCTRXAM, 0) AS ORCTRXAM,
dbo.RM00101.STATE
FROM dbo.GL_Sales_Accounts
INNER JOIN dbo.RM30301
ON dbo.GL_Sales_Accounts.DSTINDX = dbo.RM30301.DSTINDX
INNER JOIN dbo.RM30101
ON dbo.RM30301.CUSTNMBR = dbo.RM30101.CUSTNMBR
AND dbo.RM30301.DOCNUMBR = dbo.RM30101.DOCNUMBR
INNER JOIN dbo.RM00101
ON dbo.RM30101.CUSTNMBR = dbo.RM00101.CUSTNMBR
INNER JOIN dbo.RM40401
ON dbo.RM30101.RMDTYPAL = dbo.RM40401.RMDTYPAL
INNER JOIN dbo.RM00301
ON dbo.RM00101.SLPRSNID = dbo.RM00301.SLPRSNID
LEFT OUTER JOIN dbo.MC020102
ON dbo.RM30301.DOCNUMBR = dbo.MC020102.DOCNUMBR
WHERE ( CAST(dbo.RM30301.DOCNUMBR AS VARCHAR(21)) NOT IN (SELECT
CAST(
DOCNUMBR AS
VARCHAR(21)) AS
Expr1
FROM
dbo.Invoices_With_Display_Discounts) )
--RM_Sales_Open
SELECT dbo.GL_Sales_Accounts.ACTNUMBR_1,
dbo.GL_Sales_Accounts.ACTNUMBR_2,
dbo.GL_Sales_Accounts.ACTNUMBR_3,
ISNULL(dbo.MC020102.ORSLSAMT, 0) AS ORSLSAMT,
dbo.RM00101.CUSTCLAS,
dbo.RM00101.CUSTNAME,
dbo.RM00101.CUSTNMBR,
dbo.RM00101.SLPRSNID,
dbo.RM40401.DOCABREV,
dbo.RM20101.CSPORNBR,
dbo.RM20101.CURNCYID,
dbo.RM20101.DOCDATE,
dbo.RM20101.DOCNUMBR,
dbo.RM20101.GLPOSTDT,
dbo.RM20101.SLSAMNT,
dbo.RM20101.VOIDSTTS,
dbo.RM00301.SLPRSNFN,
dbo.RM00301.SPRSNSLN,
'OPEN' AS DocOrigin,
ISNULL(dbo.MC020102.ORFRTAMT, 0) AS ORFRTAMT,
dbo.RM20101.FRTAMNT,
dbo.RM00301.COMPRCNT,
dbo.RM20101.TRDISAMT,
ISNULL(dbo.MC020102.ORTDISAM, 0) AS ORTDISAM,
ISNULL(dbo.MC020102.ORMISCAMT, 0) AS ORMISCAMT,
ISNULL(dbo.MC020102.ORTAXAMT, 0) AS ORTAXAMT,
ISNULL(dbo.MC020102.ORCTRXAM, 0) AS ORCTRXAM,
dbo.RM00101.STATE
FROM dbo.GL_Sales_Accounts
INNER JOIN dbo.RM10101
ON dbo.GL_Sales_Accounts.DSTINDX = dbo.RM10101.DSTINDX
INNER JOIN dbo.RM20101
ON dbo.RM10101.CUSTNMBR = dbo.RM20101.CUSTNMBR
AND dbo.RM10101.DOCNUMBR = dbo.RM20101.DOCNUMBR
INNER JOIN dbo.RM00101
ON dbo.RM20101.CUSTNMBR = dbo.RM00101.CUSTNMBR
INNER JOIN dbo.RM40401
ON dbo.RM20101.RMDTYPAL = dbo.RM40401.RMDTYPAL
INNER JOIN dbo.RM00301
ON dbo.RM00101.SLPRSNID = dbo.RM00301.SLPRSNID
LEFT OUTER JOIN dbo.MC020102
ON dbo.RM10101.DOCNUMBR = dbo.MC020102.DOCNUMBR
WHERE ( CAST(dbo.RM20101.DOCNUMBR AS VARCHAR(21)) NOT IN (SELECT
CAST(
DOCNUMBR AS
varchar(21)) AS
Expr1
FROM
dbo.Invoices_With_Display_Discounts) )
I guess that RM_Sales_Union is a view that contains a division. The filter simply changes something like a COUNT or SUM to give zero, and it is this that is used as divisor
Change it to use something/NULLIF(..., 0) to make the expressions give NULL. Or ISNULL(something/NULLIF(..., 0), 0) to get NULL instead

Resources