Temp Table VS Table variable - sql-server

I have to write a table function so I prototyped the query in SQL Server and used a temp table but when I change it to a table variable the query goes from taking approx. 1 minute to more than 2 hours.
The second code is this one:
DECLARE #DETALLE TABLE
(
FECHA smalldatetime,
NO_OP NVARCHAR(100),
MONTO FLOAT,
PLAZO INT,
CLIENTE NVARCHAR(100)
)
-- CALCULO EL PLAZO POR EL MONTO, EL CUAL SERA EL NUMERADOR --
--DROP TABLE #DETALLE
INSERT INTO #DETALLE
SELECT
D.FECHA, D.NO_OP,
MONTO = (D.CAPITAL+D.INTERESES)/1000000,
PLAZO = CAST(D.FECHA_VCTO-D.FECHA AS INT),
CLIENTE = CASE
WHEN MIN_MAY = 'N' THEN 'MINORISTA'
WHEN M.ORIGEN = 'MESA LIQUIDEZ' THEN 'CLIENTE LIQUIDEZ'
WHEN M.ORIGEN IS NULL AND MIN_MAY = 'S' AND COD_SUCURSAL = '246' THEN 'EMPRESAS SALES'
ELSE 'OTRO MAYORISTA'
END
--INTO #DETALLE
FROM
BCI_RIF_ODS.dbo.Tab_Detalle_DAP AS D
INNER JOIN
BCI_RI_ODS.dbo.Cliente_Traduce AS C ON (C.CLIENTE_ID = D.CLIENTE_ID)
LEFT JOIN
BCI_RIF_ODS.dbo.TabMae_CliMesa AS M ON (D.CLIENTE_ID = M.CLIENTE_ID)
WHERE
FECHA >= '20180101' AND FECHA_VCTO > FECHA
SELECT
D1.CLIENTE, D1.FECHA,
NUMERADOR = SUM(D1.PLAZO*D1.MONTO),
MONTO = D2.MONTO,
FACTOR = SUM(D1.PLAZO*D1.MONTO)/D2.Monto
FROM
#DETALLE D1
LEFT JOIN
(SELECT
CLIENTE, FECHA,
MONTO = SUM(MONTO)
FROM
#DETALLE
GROUP BY
CLIENTE, FECHA) D2 ON (D1.CLIENTE = D2.CLIENTE AND D1.Fecha = D2.Fecha)
GROUP BY
D1.CLIENTE, D1.Fecha, D2.MONTO

You really don't need to make another copy of your data to then just perform an aggregate. You could use a cte here instead. Something like this will likely perform a lot better than copying data from one table to a variable.
with DETALLE as
(
-- CALCULO EL PLAZO POR EL MONTO, EL CUAL SERA EL NUMERADOR --
SELECT
D.FECHA, D.NO_OP,
MONTO = (D.CAPITAL+D.INTERESES)/1000000,
PLAZO = CAST(D.FECHA_VCTO-D.FECHA AS INT),
CLIENTE = CASE
WHEN MIN_MAY = 'N' THEN 'MINORISTA'
WHEN M.ORIGEN = 'MESA LIQUIDEZ' THEN 'CLIENTE LIQUIDEZ'
WHEN M.ORIGEN IS NULL AND MIN_MAY = 'S' AND COD_SUCURSAL = '246' THEN 'EMPRESAS SALES'
ELSE 'OTRO MAYORISTA'
END
FROM
BCI_RIF_ODS.dbo.Tab_Detalle_DAP AS D
INNER JOIN
BCI_RI_ODS.dbo.Cliente_Traduce AS C ON (C.CLIENTE_ID = D.CLIENTE_ID)
LEFT JOIN
BCI_RIF_ODS.dbo.TabMae_CliMesa AS M ON (D.CLIENTE_ID = M.CLIENTE_ID)
WHERE
FECHA >= '20180101' AND FECHA_VCTO > FECHA
)
SELECT
D1.CLIENTE, D1.FECHA,
NUMERADOR = SUM(D1.PLAZO*D1.MONTO),
MONTO = D2.MONTO,
FACTOR = SUM(D1.PLAZO*D1.MONTO)/D2.Monto
FROM
DETALLE D1
LEFT JOIN
(SELECT
CLIENTE, FECHA,
MONTO = SUM(MONTO)
FROM
DETALLE
GROUP BY
CLIENTE, FECHA) D2 ON (D1.CLIENTE = D2.CLIENTE AND D1.Fecha = D2.Fecha)
GROUP BY
D1.CLIENTE, D1.Fecha, D2.MONTO

Related

How to optimize SQL query with subqueries

I have this query that is taking a long time to execute. I would like to know how to optimize it. What slows it down are the addition subqueries.
This is the query:
SELECT DISTINCT
dbo.Ventas.IdVenta, dbo.Ventas.CodigoVenta, dbo.Ventas.Fecha_Alta, dbo.M_Operadores.Nombre + ' ' + dbo.M_Operadores.Apellidos AS Operador, SUBSTRING(dbo.Ventas.Cliente, 0, CHARINDEX(CHAR(13), dbo.Ventas.Cliente))
AS Cliente, dbo.M_Centros.Centro,
(SELECT SUM(LineaImporte) AS Expr1
FROM dbo.Ventas_Detalle
WHERE (IdVenta = dbo.Ventas.IdVenta)) - dbo.Ventas.Redondeo AS Importe,
(SELECT ISNULL(SUM(dbo.Movimientos_Caja_Detalle.Ajuste), 0) AS Ajuste
FROM dbo.Movimientos_Caja_Detalle INNER JOIN
dbo.Movimientos_Caja ON dbo.Movimientos_Caja_Detalle.IdMovimientoCaja = dbo.Movimientos_Caja.IdMovimientoCaja
WHERE (dbo.Movimientos_Caja.IdVenta = dbo.Ventas.IdVenta)) AS Ajuste,
(SELECT ISNULL(SUM(Movimientos_Caja_Detalle_2.Importe), 0) AS Cobrado
FROM dbo.Movimientos_Caja_Detalle AS Movimientos_Caja_Detalle_2 INNER JOIN
dbo.Movimientos_Caja AS Movimientos_Caja_2 ON Movimientos_Caja_Detalle_2.IdMovimientoCaja = Movimientos_Caja_2.IdMovimientoCaja
WHERE (Movimientos_Caja_2.IdVenta = dbo.Ventas.IdVenta) OR
(Movimientos_Caja_2.CodigoSobre = dbo.Ventas.CodigoSobre) AND (Movimientos_Caja_2.IdTipoMov_Caja = 7)) AS Cobrado,
(SELECT SUM(LineaImporte) AS Expr1
FROM dbo.Ventas_Detalle AS Ventas_Detalle_1
WHERE (IdVenta = dbo.Ventas.IdVenta)) - dbo.Ventas.Redondeo -
(SELECT ISNULL(SUM(Movimientos_Caja_Detalle_1.Importe), 0) AS Cobrado
FROM dbo.Movimientos_Caja_Detalle AS Movimientos_Caja_Detalle_1 INNER JOIN
dbo.Movimientos_Caja AS Movimientos_Caja_1 ON Movimientos_Caja_Detalle_1.IdMovimientoCaja = Movimientos_Caja_1.IdMovimientoCaja
WHERE (Movimientos_Caja_1.IdVenta = dbo.Ventas.IdVenta) OR
(Movimientos_Caja_1.CodigoSobre = dbo.Ventas.CodigoSobre) AND (Movimientos_Caja_1.IdTipoMov_Caja = 7)) AS Pendiente,
(SELECT Importe AS expr1
FROM dbo.Vales
WHERE (IdVentaEmision = dbo.Ventas.IdVenta)) AS Vale, dbo.Ventas.CodigoSobre, dbo.Ventas.FechaTerminado, dbo.Ventas.IdCentro_Alta AS IdCentro, dbo.Ventas.FechaEntregado, dbo.Ventas.IdOperador,
dbo.Ventas.FacturaVenta, dbo.Ventas.FechaFactura, dbo.Ventas.EstadoFactura, dbo.Ventas.TipoFactura
FROM dbo.Ventas INNER JOIN
dbo.M_Operadores ON dbo.Ventas.IdOperador = dbo.M_Operadores.IdOperador INNER JOIN
dbo.M_Centros ON dbo.Ventas.IdCentro_Alta = dbo.M_Centros.IdCentro
This is the code after changes based on comments:
SELECT
V.IdVenta, V.CodigoVenta, V.Fecha_Alta, MO.Nombre + ' ' + MO.Apellidos AS Operador, SUBSTRING(V.Cliente, 0, CHARINDEX(CHAR(13), V.Cliente))
AS Cliente, MC.Centro,
(SELECT SUM(LineaImporte) AS Expr1
FROM Ventas_Detalle
WHERE (IdVenta = V.IdVenta)) - V.Redondeo AS Importe,
(SELECT ISNULL(SUM(Movimientos_Caja_Detalle.Ajuste), 0) AS Ajuste
FROM Movimientos_Caja_Detalle INNER JOIN
Movimientos_Caja ON Movimientos_Caja_Detalle.IdMovimientoCaja = Movimientos_Caja.IdMovimientoCaja
WHERE (Movimientos_Caja.IdVenta = V.IdVenta)) AS Ajuste,
(SELECT ISNULL(SUM(Movimientos_Caja_Detalle_2.Importe), 0) AS Cobrado
FROM Movimientos_Caja_Detalle AS Movimientos_Caja_Detalle_2 INNER JOIN
Movimientos_Caja AS Movimientos_Caja_2 ON Movimientos_Caja_Detalle_2.IdMovimientoCaja = Movimientos_Caja_2.IdMovimientoCaja
WHERE (Movimientos_Caja_2.IdVenta = V.IdVenta) OR
(Movimientos_Caja_2.CodigoSobre = V.CodigoSobre) AND (Movimientos_Caja_2.IdTipoMov_Caja = 7)) AS Cobrado,
(SELECT SUM(LineaImporte) AS Expr1
FROM Ventas_Detalle AS Ventas_Detalle_1
WHERE (IdVenta = V.IdVenta)) - V.Redondeo -
(SELECT ISNULL(SUM(Movimientos_Caja_Detalle_1.Importe), 0) AS Cobrado
FROM Movimientos_Caja_Detalle AS Movimientos_Caja_Detalle_1 INNER JOIN
Movimientos_Caja AS Movimientos_Caja_1 ON Movimientos_Caja_Detalle_1.IdMovimientoCaja = Movimientos_Caja_1.IdMovimientoCaja
WHERE (Movimientos_Caja_1.IdVenta = V.IdVenta) OR
(Movimientos_Caja_1.CodigoSobre = V.CodigoSobre) AND (Movimientos_Caja_1.IdTipoMov_Caja = 7)) AS Pendiente,
(SELECT Importe AS expr1
FROM Vales
WHERE (IdVentaEmision = V.IdVenta)) AS Vale, V.CodigoSobre, V.FechaTerminado, V.IdCentro_Alta AS IdCentro, V.FechaEntregado, V.IdOperador,
V.FacturaVenta, V.FechaFactura, V.EstadoFactura, V.TipoFactura
FROM Ventas V INNER JOIN
M_Operadores MO ON V.IdOperador = MO.IdOperador INNER JOIN
M_Centros MC ON V.IdCentro_Alta = MC.IdCentro

Write query with subquery in CodeIgniter4 Query Builder?

I have the following query which has an issue with Query Builder.
SELECT IIF(ISNULL(MAX(CODCLIENTE), 0) + 1 = 1,
(SELECT VALOR + 1
FROM PARAMETROS
WHERE LTRIM(RTRIM(SUBCLAVE)) = 'MINIM'
AND USUARIO = '1'),
ISNULL(MAX(CODCLIENTE), 0) + 1)
FROM CLIENTES
WHERE CODCLIENTE >= (SELECT VALOR
FROM PARAMETROS
WHERE LTRIM(RTRIM(SUBCLAVE)) = 'MINIM'
AND USUARIO = '1')
AND CODCLIENTE <= (SELECT VALOR
FROM PARAMETROS
WHERE LTRIM(RTRIM(SUBCLAVE)) = 'MAXIM'
AND USUARIO = '1');
Is there any way to do it with Query Builder? I'm currently using this method.

Stored Procedure show the same value for each of the rows

I am having problem where one particular column shows the same value for all the rows. For example, I would like to check which person in charge of what item. How can I do that ?
As you can see in the screenshot, I managed to retrieve the two location however the officername is the same for all rows.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SearchDevice]
#DeviceID AS INT,
#DeviceImei AS VARCHAR(50),
#StationID AS INT,
#ID AS INT,
#OfficerName AS VARCHAR(50)
AS
BEGIN
SELECT
D.imei, L.*, L1.*
FROM
Device D
INNER JOIN
Box on Box.DeviceID = D.ID
INNER JOIN
Station on Box.StationID = Station.ID
INNER JOIN
Officer on Officer.StationID = Station.ID
INNER JOIN
Role on Role.ID = Officer.RoleID
INNER JOIN
Division on Officer.DivisionID = Division.ID
OUTER APPLY
(SELECT TOP 1 *
FROM dbo.Location L1
WHERE L1.DeviceImei = D.Imei
GROUP BY DeviceImei, Latitude, Longitude, Distance, LocationSend
ORDER BY (LocationSend) DESC) AS L
OUTER APPLY
(SELECT TOP 1
L6.StationID AS 'Station', L3.Name, L5.Id AS 'BoxID',
L6.Username AS 'Name', L3.ID AS 'DivisionID'
FROM
[dbo].[Division] L3, dbo.Station L4, dbo.Box L5, dbo.Officer L6,dbo.Role L7
WHERE
L.Latitude IS NOT NULL
AND L.Longitude IS NOT NULL
AND L.Distance IS NOT NULL
AND L.DeviceImei = D.ImeI
AND D.ID = L5.DeviceID
AND L4.ID = L5.StationID
AND L3.ID = L4.[EDivisionID ]
AND L4.ID = L6.StationID
AND L3.ID = L6.DivisionID
GROUP BY
l6.StationID, L3.Name, L5.Id, L6.Username, L3.ID) AS L1
WHERE
D.ID = Box.DeviceID
AND Officer.StationID = Station.ID
AND Officer.RoleID = Role.ID
AND Officer.DivisionID = ElectoralDivision.ID
AND D.ID = #DeviceID
OR L.DeviceImei = #DeviceImei
OR L1.Station = #StationID
OR L1.DivisionID = #DivisionID
OR L1.OfficerName = #OfficerName
END

Perfomance of SELECT-query with branch in WHERE-clause

I've a following legacy SP:
CREATE PROCEDURE dbo.get_orders_history
(
#FirstDt DATETIME2(6),
#LastDt DATETIME2(6),
#Class VARCHAR(12),
#PeriodType SMALLINT
)
AS
SET NOCOUNT ON
CREATE TABLE #BufferTable (OrderId INT)
INSERT INTO #BufferTable
SELECT DISTINCT
O.OrderId
FROM
BaseOrders O JOIN Classes C ON O.ClassId = C.ClassId
WHERE
(O.Changed = 0) AND
(C.ClassCode = #ClassCode) AND
(
(#PeriodType = 1 AND O.LastActionDateTime >= #FirstDt AND O.OrderDateTime < #LastDt) OR
(#PeriodType = 2 AND O.OrderDateTime >= #FirstDt AND O.OrderDateTime <= #LastDt)
)
OPTION(RECOMPILE);
SELECT A.Column,
C.Column,
OB.Column1,
...
OB.Column10,
O.Column1,
...
O.Column100,
FROM BaseOrders OB
JOIN #BufferTable IDL ON (OB.OrderId = IDL.OrderId)
JOIN Orders O ON (O.OrderId = IDL.OrderId)
JOIN Classes C ON (O.ClassId = C.ClassId)
ORDER BY
O.OrderId
DROP TABLE #BufferTable
GO
The parameter 'PeriodType' is to be added now and I doubt whether this way of make branch (condition in WHERE-clause) is efficient.
SP is rarely called but returns a lot of rows (100K+), so I think OPTION RECOMPILE for SELECT is reasonable solution in this case.
Could any of SQL experts suggest more efficient way to implement such branch?
--
EDIT: I will clarify that current prod version of SP has no parameter 'Period type' and WHERE is following:
WHERE
(O.Changed = 0) AND
(C.ClassCode = #ClassCode) AND
(O.LastActionDateTime >= #FirstDt AND O.OrderDateTime < #LastDt)
My goal is to implement two types of date range type in current SP without or with minimal performance penalties.
Did you try removing OR from the initial insert and deleting afterwards with negation? Here is a code snippet.
CREATE TABLE #BufferTable (OrderId INT, LastActionDateTime datetime, OrderDateTime datetime)
INSERT INTO #BufferTable
SELECT DISTINCT
o.OrderId
, o.LastActionDateTime
, o.OrderDateTime
FROM
BaseOrders O JOIN Classes C ON O.ClassId = C.ClassId
WHERE
(O.Changed = 0) AND
(C.ClassCode = #ClassCode);
delete p
from #BufferTable p
where not
(
(#PeriodType = 1 AND p.LastActionDateTime >= #FirstDt AND p.OrderDateTime < #LastDt) OR
(#PeriodType = 2 AND p.OrderDateTime >= #FirstDt AND p.OrderDateTime <= #LastDt)
)

Stored procedure returning duplicate rows with one column empty

I have a stored procedure
ALTER PROCEDURE [dbo].[solar_zip_tier_acl_zip_export]
#affiliate_id int
AS
BEGIN
SET NOCOUNT ON;
declare #tier_date varchar(6)
exec solar_zip_tier_select_active_date #tier_date output
SELECT DISTINCT
zip,
state
FROM solar_zip_tier_mapping_view sztm (NOLOCK)
JOIN solar_zip_tier_acl acl (NOLOCK)
ON acl.tier_id = sztm.tier_id
AND (acl.buyer_id = sztm.buyer_id
OR acl.buyer_id = 0)
JOIN buyers b (NOLOCK)
ON b.buyer_id = sztm.buyer_id
JOIN solar_zip_tiers szt (NOLOCK)
ON szt.tier_id = sztm.tier_id
WHERE sztm.tier_date = #tier_date
AND acl.affiliate_id = #affiliate_id
AND sztm.active > 0
AND b.active > 0
AND szt.active > 0
ORDER BY zip
The way it returns result is
Zip State
01001
01001 MA
01002
01002 MA
01003
01003 MA
It is resulting in 2 rows, one with state in it and other with no state, how do I modify it, so it results only in the row with the data?
I want result as
Zip State
01001 MA
01002 MA
01003 MA
SELECT DISTINCT
zip,
state
FROM solar_zip_tier_mapping_view sztm (NOLOCK)
JOIN solar_zip_tier_acl acl (NOLOCK)
ON acl.tier_id = sztm.tier_id
AND (acl.buyer_id = sztm.buyer_id
OR acl.buyer_id = 0)
JOIN buyers b (NOLOCK)
ON b.buyer_id = sztm.buyer_id
JOIN solar_zip_tiers szt (NOLOCK)
ON szt.tier_id = sztm.tier_id
WHERE sztm.tier_date = #tier_date
AND acl.affiliate_id = #affiliate_id
AND sztm.active > 0
AND b.active > 0
AND szt.active > 0
AND STATE IS NOT NULL AND STATE IS NOT ''
ORDER BY zip

Resources