SQL Server: Join tables in a loop going through table rows - sql-server

I have a table with the following fiels: PicklistTable, PicklistColumnName, FormTable and FormColumnName. FormColumnName is a foreign key into PicklistTable that I need to join on PicklistColumnName. Basically I need to find out how many times each picklist values has been used on all forms that reference that picklist. So the query would look something like this (maybe??):
SELECT PicklistColumnName, count(FormColumnName1) + count(FormColumnName2) as Count
FROM PicklistTable
INNER JOIN FormTable1 ON PicklistColumnName = FormColumnName1
INNER JOIN FormTable2 ON PicklistColumnName = FormColumnName2
GROUP BY PicklistColumnName
Here is an example table:
PicklistTable PicklistColumnName FormTable FormColumnName
tblEthnicityValues Ethnicity_ID tblContact Contact_Ethnicity_ID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAC FatherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAC MotherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAYP EthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAYP FatherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACIHAYP MotherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACRHAC FatherEthnicityID
tblEthnicityValues Ethnicity_ID udfOHFTCYPLACRHAC MotherEthnicityID
So I would in this case need to join tblContact, udfOHFTCYPLACIHAC etc on Contact_Ethnicity_ID, FatherEthnicityID etc.
Can someone please help? I hope I explained it well enough.
Thanks!
Tanya

Assuming that the PicklistColumnName from PicklistTable table need not be present in both FormTable1 and FormTable2 tables, this query might solve your problem.
SELECT pt.PicklistColumnName, count(ft1.FormColumnName1) + count(ft2.FormColumnName2) as Count
FROM PicklistTable pt
LEFT OUTER JOIN FormTable1 ft1
ON pt.PicklistColumnName = ft1.FormColumnName1
LEFT OUTER JOIN FormTable2 ft2
ON pt.PicklistColumnName = ft2.FormColumnName2
GROUP BY pt.PicklistColumnName

Do you want to get the following SQL:
DECLARE #tb TABLE(PicklistTable VARCHAR(30),PicklistColumnName VARCHAR(30),FormTable VARCHAR(30),FormColumnName VARCHAR(30) )
INSERT INTO #tb(PicklistTable,PicklistColumnName,FormTable,FormColumnName)
SELECT 'tblEthnicityValues','Ethnicity_ID','tblContact','Contact_Ethnicity_ID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAC','FatherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAC','MotherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAYP','EthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAYP','FatherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACIHAYP','MotherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACRHAC','FatherEthnicityID' UNION
SELECT 'tblEthnicityValues','Ethnicity_ID','udfOHFTCYPLACRHAC','MotherEthnicityID'
DECLARE #sql VARCHAR(max)
SELECT #sql='SELECT '+t.PicklistColumnName+',(0'+t.subCountSQL+') AS'+CHAR(13)+'Count FROM '+t.PicklistTable+CHAR(13)+t.subSQL FROM (
SELECT DISTINCT PicklistTable,PicklistColumnName,t2.* ,t3.*
FROM #tb AS t1
CROSS APPLY(SELECT 'INNER JOIN '+FormTable+' ON PicklistColumnName='+tt.FormTable+'.'+tt.FormColumnName+' '
FROM #tb AS tt WHERE tt.PicklistTable=t1.PicklistTable AND tt.PicklistColumnName=t1.PicklistColumnName
FOR XML PATH('')
) AS t2(subSQL)
CROSS APPLY(SELECT '+COUNT('+tt.FormTable+'.'+tt.FormColumnName +')'
FROM #tb AS tt WHERE tt.PicklistTable=t1.PicklistTable AND tt.PicklistColumnName=t1.PicklistColumnName
FOR XML PATH('')
) AS t3(subCountSQL)
)AS t
PRINT #sql
EXEC(#SQL)
The variable #SQL will be :
SELECT Ethnicity_ID,(0+COUNT(tblContact.Contact_Ethnicity_ID)+COUNT(udfOHFTCYPLACIHAC.FatherEthnicityID)+COUNT(udfOHFTCYPLACIHAC.MotherEthnicityID)+COUNT(udfOHFTCYPLACIHAYP.EthnicityID)+COUNT(udfOHFTCYPLACIHAYP.FatherEthnicityID)+COUNT(udfOHFTCYPLACIHAYP.MotherEthnicityID)+COUNT(udfOHFTCYPLACRHAC.FatherEthnicityID)+COUNT(udfOHFTCYPLACRHAC.MotherEthnicityID)) AS Count FROM tblEthnicityValues
INNER JOIN tblContact ON PicklistColumnName=tblContact.Contact_Ethnicity_ID INNER JOIN udfOHFTCYPLACIHAC ON PicklistColumnName=udfOHFTCYPLACIHAC.FatherEthnicityID INNER JOIN udfOHFTCYPLACIHAC ON PicklistColumnName=udfOHFTCYPLACIHAC.MotherEthnicityID INNER JOIN udfOHFTCYPLACIHAYP ON PicklistColumnName=udfOHFTCYPLACIHAYP.EthnicityID INNER JOIN udfOHFTCYPLACIHAYP ON PicklistColumnName=udfOHFTCYPLACIHAYP.FatherEthnicityID INNER JOIN udfOHFTCYPLACIHAYP ON PicklistColumnName=udfOHFTCYPLACIHAYP.MotherEthnicityID INNER JOIN udfOHFTCYPLACRHAC ON PicklistColumnName=udfOHFTCYPLACRHAC.FatherEthnicityID INNER JOIN udfOHFTCYPLACRHAC ON PicklistColumnName=udfOHFTCYPLACRHAC.MotherEthnicityID

Related

Why Inner Join worked as Cross Join in SQL Server?

I am trying to join several tables using INNER JOIN.
Here is code
IF OBJECT_ID('tempdb..#tmpRecData') IS NOT NULL
DROP TABLE #tmpRecData
--STEP 1
SELECT DISTINCT
pr.ChainID, pr.StoreID, pr.SupplierID, pr.ProductID,
MAX(CAST(pr.ActiveLastDate AS date)) AS 'Active Date'
--ChainID, SupplierID, StoreID, InvoiceDate, InvoiceNumber, SupplierInvoiceDate, SupplierInvoiceNumber
INTO
#tmpRecData
FROM
dbo.[ProductPrices_Retailer] AS pr
LEFT JOIN
ProductIdentifiers iden ON pr.ProductID = iden.ProductID
AND iden.ProductIdentifierTypeID = 2
WHERE
pr.ChainID = '119121'
AND pr.ActiveLastDate > '12/01/2016'
GROUP BY
pr.ProductID, pr.ProductName, iden.IdentifierValue,
pr.ChainID, pr.StoreID, pr.SupplierID
--STEP 2
SELECT
rec.ChainID, rec.StoreID, rec.SupplierInvoiceNumber,
rec.TransactionTypeID, rec.SupplierID, rec.SaleDateTime,
rec.ProductID, rec.UPC, rec.ProductDescriptionReported,
rec.RawProductIdentifier
FROM
#tmpRecData t
INNER JOIN
dbo.StoreTransactions AS rec WITH (NOLOCK) ON rec.ChainID = T.ChainID
WHERE
rec.ChainID = '119121'
DROP TABLE #tmpRecData
I am getting 4096 (Step1) * 145979 (Step2) = 725077693 rows (725 million)
This is a huge number of records, but I have used INNER JOIN, so why it worked as CROSS JOIN?
CROSS JOIN is very different to INNER JOIN.
INNER JOIN displays only the rows that have a match in both the joined tables..
CROSS JOIN produces a Cartesian product of the tables in the join. The number of rows of the result is the number of the rows in first table multiplied by the number of rows in the second table.
You need to join with store ID in step2 for this to work. It is running chainID for every store , hence too many number of records. If products also need to match, then you need to Join productID as well in step2
IF OBJECT_ID('tempdb..#tmpRecData') IS NOT NULL DROP TABLE #tmpRecData
--STEP 1
SELECT DISTINCT pr.ChainID,pr.StoreID,pr.SupplierID,pr.ProductID, MAX(CAST(pr.ActiveLastDate AS date)) AS 'Active Date'
--ChainID, SupplierID, StoreID, InvoiceDate, InvoiceNumber, SupplierInvoiceDate, SupplierInvoiceNumber
INTO #tmpRecData
FROM dbo.[ProductPrices_Retailer] AS pr
LEFT JOIN ProductIdentifiers iden
ON pr.ProductID=iden.ProductID
AND iden.ProductIdentifierTypeID=2
WHERE pr.ChainID='119121'
AND pr.ActiveLastDate>'12/01/2016'
GROUP BY pr.ProductID,pr.ProductName,iden.IdentifierValue,pr.ChainID,pr.StoreID,pr.SupplierID
--STEP 2
SELECT rec.ChainID,rec.StoreID,rec.SupplierInvoiceNumber,rec.TransactionTypeID,rec.SupplierID,rec.SaleDateTime,
rec.ProductID,rec.UPC,rec.ProductDescriptionReported,rec.RawProductIdentifier
FROM #tmpRecData t
INNER JOIN dbo.StoreTransactions AS rec WITH (NOLOCK)
ON rec.ChainID=T.ChainID and rec.StoreID = T.storeID
WHERE rec.ChainID='119121'
DROP TABLE #tmpRecData

Optimize Nested Select query

How to optimize the following query to be work better :
SELECT c.a1,c.a2,
(SELECT SUM(t2.TempOB) FROM tbl1 t2 WHERE t2.AccNo LIKE CONCAT( C.AccNo,'%') )OB,
(SELECT SUM(t3.TempDebit) FROM tbl1 t3 WHERE t3.AccNo LIKE CONCAT( C.AccNo,'%') ) Debit,
(SELECT SUM(t4.TempCredit) FROM tbl1 t4 WHERE t4.AccNo LIKE CONCAT( C.AccNo,'%') ) Credit
FROM tbl1 C WHERE AccLevel= #Level
You can use as the below:
SELECT
A.a1,
A.a2,
SUM(B.OB) AS OB,
SUM(B.Debit) AS Debit,
SUM(B.Credit) AS Credit
FROM
tbl1 A LEFT JOIN
tbl1 B ON B.AccNo LIKE A.AccNo + '%'
WHERE
A.AccLevel = #Level
GROUP BY
A.a1,
A.a2

What are other ways to get this result set

What are other ways to get the same result set
I am using 4 tables
SELECT * FROM Terminal
SELECT * FROM Customer
SELECT * FROM Contract
SELECT * FROM ExternalTable
Data in these 4 tables are as below:
The query that i've written is
select ex.TerminalName,ex.CustomerName from ExternalTable ex
except
select t.TerminalName,ct.CustomerName from [Contract] c
inner join Terminal t on t.TerminalID=c.TerminalID
inner join Customer ct on ct.CustomerId=c.CustomerId
Which gets the below result
So just curious to know what are the other ways to get this same result
I'm not really what you are looking for, but here is another way to write the query that should produce the same results:
SELECT
ex.TerminalName,
ex.CustomerName
FROM
ExternalTable ex
WHERE
NOT EXISTS( SELECT
NULL
FROM
[Contract] c
INNER JOIN
Terminal t on t.TerminalID = c.TerminalID
INNER JOIN
Customer ct on ct.CustomerId = c.CustomerId
WHERE
t.TerminalName = ex.TerminalName
AND
ex.CustomerName = ct.CustomerName
)
This ought to be equivalent:
select ex.TerminalName,ex.CustomerName
from
ExternalTable ex
left outer join
(
[Contract] c
inner join Terminal t
on t.TerminalID=c.TerminalID
inner join Customer ct
on ct.CustomerId=c.CustomerId
)
on ex.TerminalName = t.TerminalName and ex.CustomerName = ct.CustomerName
where t.TerminalName is null and ct.CustomerName is null
You should note that except returns distinct results and to be strictly equivalent I would need to specify select distinct.
Here is a self-contained example that shows two alternatives.
One uses NOT IN, and the other uses a LEFT OUTER JOIN, but they should be equivalent.
--set up temp tables with dummy data to replicate the issue
declare #Terminal table(terminalid int,terminalname nvarchar(100));
insert into #Terminal select 1,'Terminal1' union select 2,'Terminal2'
declare #Customer table(customerid int,customername nvarchar(100));
insert into #Customer select 1,'Customer1' union select 2,'Customer2';
declare #Contract table(contractid int,terminalid int,customerid int,contractname nvarchar(100));
insert into #Contract select 1,1,1,'Contract1';
declare #ExternalTable table(externalid int,terminalname nvarchar(100),customername nvarchar(100),contractname nvarchar(100));
insert into #ExternalTable select 1,'Terminal1','Customer1','Contract1' union select 2,'Terminal2','Customer1','Contract1'
--SELECT * FROM #Terminal
--SELECT * FROM #Customer
--SELECT * FROM #Contract
--SELECT * FROM #ExternalTable
--goal: show records that are in the external table, but are not fully linked in the other tables
--original
select ex.TerminalName,ex.CustomerName from #ExternalTable ex
except
select t.TerminalName,ct.CustomerName from #Contract c
inner join #Terminal t on t.TerminalID=c.TerminalID
inner join #Customer ct on ct.CustomerId=c.CustomerId
--revised (left outer join method)
select et.TerminalName,et.CustomerName
from
#ExternalTable et
left join (
select ex.externalid
from
#Contract c
inner join #Terminal t on t.TerminalID=c.TerminalID
inner join #Customer ct on ct.CustomerId=c.CustomerId
inner join #ExternalTable ex on ex.terminalname = t.terminalname and ex.customername = ct.customername
) excludes on excludes.externalid = et.externalid
where excludes.externalid is null
--revised ("not in" method)
select et.TerminalName,et.CustomerName
from
#ExternalTable et
where et.externalid not in(
select ex.externalid
from
#Contract c
inner join #Terminal t on t.TerminalID=c.TerminalID
inner join #Customer ct on ct.CustomerId=c.CustomerId
inner join #ExternalTable ex on ex.terminalname = t.terminalname and ex.customername = ct.customername
)

TSQL Rewrite UNION into JOIN

I'm new to SQL and I'm trying to rewrite this query so that it uses a join instead of a union
DECLARE #user VARCHAR(255) = 'jSmith'
DECLARE #dept VARCHAR(255) = 'produce'
SELECT DISTINCT A.*
FROM goals A
INNER JOIN managers B ON B.name = #user
WHERE #user IN (A.userName,A.managerUserName)
AND dept = #dept
AND yr = '2016'
UNION
SELECT DISTINCT A.*
FROM goals A
INNER JOIN managers C ON C.name = #user
INNER JOIN committedGoals B ON A.goalID = B.goalID
WHERE dept LIKE #dept + '%'
AND yr = '2016'
This is not exactly the same because you've restricted the second part of the query to records that contain a record in committedGoals, but if you always have a record, then this might work for you:
SELECT g.*
FROM goals g
LEFT JOIN managers m
ON g.managerUserName=m.name
WHERE dept LIKE #dept + '%'
AND yr='2016'
AND (g.managerUserName=#user OR m.name=#user)

Get the most value from another column

I want to get data historical and the production. My stored procedure is as follows:
ALTER PROCEDURE [dbo].[pCaRptACInactivas](
#CodAsesor VARCHAR(15),
#CodOficina VARCHAR(4))
AS
SET NOCOUNT ON
DECLARE #CodArbolConta VARCHAR(25)
IF #CodOficina = '%'
SET #CodArbolConta = '%'
ELSE
SELECT #CodArbolConta = CodArbolConta + '%' FROM tClOficinas WHERE CodOficina LIKE #CodOficina
SELECT
tabACInactivas.CodOficina,
tabACInactivas.NomOficina,
tabACInactivas.NomAsesor,
MAX(tabACInactivas.CodPrestamo) CodPrestamo,
tabACInactivas.CodAsociacion,
tabACInactivas.NombreAsociacion,
MAX(tabACInactivas.Ciclo) AS Ciclo,
COUNT(DISTINCT tabACInactivas.CodUsuario) AS CantSocias,
MAX(tabACInactivas.FechaEstado) AS FechaCancelacion--,
FROM ( SELECT tClOficinas.CodOficina, tClOficinas.NomOficina, tCaClAsesores.CodAsesor, tCaClAsesores.NomAsesor, tCaPrestamos.CodPrestamo, tCaAsociacion.CodAsociacion, tCaAsociacion.NombreAsociacion, tCaPrestamos.Ciclo, tCaPrCliente.CodUsuario, tCaPrestamos.FechaEstado, tClParametros.FechaProceso FROM tCaPrestamos WITH(NOLOCK) INNER JOIN tCaProducto WITH(NOLOCK) ON tCaProducto.CodProducto = tCaPrestamos.CodProducto INNER JOIN tClOficinas WITH(NOLOCK) ON tClOficinas.CodOficina = tCaPrestamos.CodOficina INNER JOIN tCaAsociacion WITH(NOLOCK) ON tCaAsociacion.CodAsociacion = tCaPrestamos.CodAsociacion INNER JOIN tCaPrCliente WITH(NOLOCK) ON tCaPrCliente.CodPrestamo = tCaPrestamos.CodPrestamo INNER JOIN tClParametros WITH(NOLOCK) ON tClParametros.CodOficina = tClOficinas.CodOficina INNER JOIN tCaClAsesores ON tCaClAsesores.CodAsesor = tCaAsociacion.CodAsesor WHERE tCaPrestamos.Estado = 'CANCELADO' AND DATEDIFF(DAY, tCaPrestamos.FechaEstado, tClParametros.FechaProceso) > 30 AND NOT EXISTS(SELECT 1
FROM tCaPrestamos Pr
INNER JOIN tCaPrCliente PrCl ON PrCl.CodPrestamo = Pr.CodPrestamo
WHERE Pr.Estado NOT IN ('TRAMITE', 'APROBADO')
AND Pr.FechaDesembolso >= tCaPrestamos.FechaEstado
AND Pr.CodAsociacion = tCaPrestamos.CodAsociacion
) AND tCaProducto.Tecnologia = 3 AND tCaPrestamos.CodAsesor LIKE #CodAsesor AND tCaPrestamos.CodOficina IN (SELECT CodOficina FROM tClOficinas WHERE CodArbolConta LIKE #CodArbolConta)
UNION ALL
SELECT tClOficinas.CodOficina, tClOficinas.NomOficina, tCaClAsesores.CodAsesor, tCaClAsesores.NomAsesor, tCaHPrestamos.CodPrestamo, tCaAsociacion.CodAsociacion, tCaAsociacion.NombreAsociacion, tCaHPrestamos.Ciclo, tCaHPrCliente.CodUsuario, tCaHPrestamos.FechaEstado, tClParametros.FechaProceso FROM tCaHPrestamos WITH(NOLOCK) INNER JOIN tCaProducto WITH(NOLOCK) ON tCaProducto.CodProducto = tCaHPrestamos.CodProducto INNER JOIN tClOficinas WITH(NOLOCK) ON tClOficinas.CodOficina = tCaHPrestamos.CodOficina INNER JOIN tCaAsociacion WITH(NOLOCK) ON tCaAsociacion.CodAsociacion = tCaHPrestamos.CodAsociacion INNER JOIN tCaHPrCliente WITH(NOLOCK) ON tCaHPrCliente.CodPrestamo = tCaHPrestamos.CodPrestamo INNER JOIN tClParametros WITH(NOLOCK) ON tClParametros.CodOficina = tClOficinas.CodOficina INNER JOIN tCaClAsesores ON tCaClAsesores.CodAsesor = tCaAsociacion.CodAsesor WHERE tCaHPrestamos.Estado = 'CANCELADO' AND DATEDIFF(DAY, tCaHPrestamos.FechaEstado, tClParametros.FechaProceso) > 30 AND NOT EXISTS(SELECT 1
FROM tCaHPrestamos Pr
INNER JOIN tCaHPrCliente PrCl ON PrCl.CodPrestamo = Pr.CodPrestamo
WHERE Pr.Estado NOT IN ('TRAMITE', 'APROBADO')
AND Pr.FechaDesembolso >= tCaHPrestamos.FechaEstado
AND Pr.CodAsociacion = tCaHPrestamos.CodAsociacion
) AND tCaProducto.Tecnologia = 3 AND tCaHPrestamos.CodAsesor LIKE #CodAsesor AND tCaHPrestamos.CodOficina IN (SELECT CodOficina FROM tClOficinas WHERE CodArbolConta LIKE #CodArbolConta)
)tabACInactivas
GROUP BY tabACInactivas.CodAsociacion, tabACInactivas.NombreAsociacion, tabACInactivas.NomOficina, tabACInactivas.CodOficina, tabACInactivas.NomAsesor
I want the CantSocias column takes the most value of the Ciclo column, but not working
That stored procedure that you have posted up is way too large and blocky to even try to interpret and understand. So I will go off of your last sentence:
I want the CantSocias column takes the most value of the Ciclo column,
but not working
Basically if you want to set a specific column to that, you can do something like this:
update YourTable
set CantSocias =
(
select max(Ciclo)
from YourOtherTable
)
-- here is where you can put a conditional WHERE clause
You may need to create a sub query to get the most value of Ciclo and join back to your query.
An example of what I mean is here:
create table #Product
(
ID int,
ProductName varchar(20)
)
insert into #Product(ID, ProductName)
select 1,'ProductOne'
union
select 2,'ProductTwo'
create table #ProductSale
(
ProductID int,
Number int,
SalesRegion varchar(20)
)
insert into #ProductSale(ProductID,Number,SalesRegion)
select 1,1500,'North'
union
select 1, 1200, 'South'
union
select 2,2500,'North'
union
select 2, 3200, 'South'
--select product sales region with the most sales
select * from #Product p
select ProductId, Max(Number) as Bestsale from #ProductSale ps group by ProductID
--combining
select
p.ID,
p.ProductName,
tp.Bestsale,
ps.SalesRegion
from
#Product p
inner join
(select ProductId, Max(Number) as Bestsale from #ProductSale ps group by ProductID) as tp on p.ID = tp.ProductID
inner join
#ProductSale ps on p.ID = ps.ProductID and tp.Bestsale = ps.Number

Resources