SQL Cross Join and IIF(ISNULL) - Not Working as Expected - sql

I'm writing a query with a report file, an employee file and a report distribution file. I would like a list of employee names, each with every report name and a 0 if they don't get the report and a 1 if they do get the report.
select distinct ut.user_name
, ut.emailaddress
, r.name
, iif(ISNULL(rd.employeeid,0)=0, 0,1) AS currentreport
from US_usertable ut
cross join DL_reports r
left outer join DL_Reptdistrib rd
on ut.employeeID = rd.employeeid
For each user, I get a complete set of reports - so the cross join works - but either they get a 1 for all the reports or a 0 for all their reports. I don't understand why this query isn't working. Kindly help if you can. Thanks in advance!!!

I think you are missing a join condition on the report:
select ut.user_name, ut.emailaddress, r.name,
(case when rd.employeeid is null then 0 else 1 end) as currentreport
from US_usertable ut cross join
DL_reports r left outer join
DL_Reptdistrib rd
on ut.employeeID = rd.employeeid and r.?? = rd.??;
The ?? is for the field used to identify the report. I might guess that it is reportID.
Note: I switched the syntax to standard SQL. IIF() is in SQL Server for compatibility with MS Access (why Microsoft didn't put the ANSI standard case in MS Access is beyond me). I also replaced ISNULL() with the ANSI standard IS NULL.

Related

SQL Server : multi-join with tuple IN clause

I'm trying to join 4 tables that have a somewhat complex relationship. Because of where this will be used, it needs to be contained in a single query, but I'm having trouble since the primary query and the IN clause query both join 2 tables together and the lookup is on two columns.
The goal is to input a SalesNum and SalesType and have it return the Price
Tables and relationships:
sdShipping
SalesNum[1]
SalesType[2]
Weight[3]
sdSales
SalesNum[1]
SalesType[2]
Zip[4]
spZones
Zip[4]
Zone[5]
spPrices
Zone[5]
Price
Weight[3]
Here's my latest attempt in T-SQL:
SELECT
spp.Price
FROM
spZones AS spz
LEFT OUTER JOIN
spPrices AS spp ON spz.Zone = spp.Zone
WHERE
(spp.Weight, spz.Zip) IN (SELECT ship.Weight, sales.Zip
FROM sdShipping AS ship
LEFT OUTER JOIN sdSales AS sales ON sales.SalesNum = ship.SalesNum
AND sales.SalesType = ship.SalesType
WHERE sales.SalesNum = (?)
AND ship.SalesType = (?));
SQL Server Management Studio says I have an error in my syntax near ',' (appropriately useless error message). Does anybody have any idea whether this is even allowed in Microsoft's version of SQL? Is there perhaps another way to accomplish it? I've seen the multi-key IN questions answered on here, but never in the case where both sides require a JOIN.
Many databases do support IN on tuples. SQL Server is not one of them.
Use EXISTS instead:
SELECT spp.Price
FROM spZones spz LEFT OUTER JOIN
spPrices spp
ON spz.Zone = spp.Zone
WHERE EXISTS (SELECT 1
FROM sdShipping ship LEFT JOIN
sdSales sales
ON sales.SalesNum = ship.SalesNum AND
sales.SalesType = ship.SalesType
WHERE spp.Weight = ship.Weight AND spz.Zip = sales.Zip AND
sales.SalesNum = (?) AND
ship.SalesType = (?)
);

How to create a query using Access from a given SQL

Someone gave me the following SQL and wants me to do a query using Access, so that it returns the information that they need. All dbo_**** are databases where they get the information from.
I tried to do the following SQL using a design view, but its not working, the datasheet(table) doesnt match the information.
I get lost in the lines LEFT OUTER JOIN ... I dont know what to do with anything after that. Can someone help me, please ?
Or if someone someone can edit the SQL so that it works on Access just copying in the SQL view mode.
Thank you.
Declare #data datetime
set #data = '2013-12-31'
--Fundos
SELECT
RelCliSFN.CdCrt,
MC5.Nome 'NomeCarteira',
MC5.CGC 'CNPJCarteira',
player_adm.NomeCurto 'Administrador',
RelCliSFN.Cliente,
CE5.Nome 'NomeCliente',
CE5.CPFCGC 'CPF/CNPJCliente',
VigRelCliSFN.DtIni,
VigRelCliSFN.DtFim
FROM
RelCliSFN
Inner JOIN MC5 ON MC5.Carteira = RelCliSFN.CdCrt
INNER JOIN MC5Auxiliar ON MC5.Carteira = MC5Auxiliar.Carteira
Inner Join VigRelCliSFN ON RelCliSFN.IdRelCliSFN = VigRelCliSFN.IdRelCliSFN
Inner Join CE5 ON CE5.Cliente=RelCliSFN.Cliente
LEFT OUTER JOIN PlayAdmxMC5 ON MC5.Carteira = PlayAdmxMC5.CdCrt AND PlayAdmxMC5.DtIniVig =
(SELECT MAX(DtIniVig) FROM PlayAdmxMC5 WHERE MC5.Carteira = CdCrt AND DtIniVig < MC5.DataAtual)
INNER JOIN Player player_adm ON PlayAdmxMC5.IdPlayAdm = player_adm.ID
WHERE
--MC5Auxiliar.bNaoExpCCSFN is null
((VigRelCliSFN.DtIni <= #data)
and ((VigRelCliSFN.DtFim >= #data) or (VigRelCliSFN.DtFim is null)))
and MC5.CGC <> 0
and CE5.Assessor not in (17, 99)
and CE5.CPFCGC <>0
and MC5.TipoCarteira <> 4
--and RelCliSFN.CdCrt = 3`
As the others already mentioned, your query has MS SQL-Server syntax. So there are three ways you could solve your problem.
Solution 1:
Create a view in the SQL-Server database.
To do this, open your SQL-Server Management Studio. Go to YourServer > databases > YourDatabase > views. Right click on "views" and then select "new view...". Close the "add table" window. Copy your sql-code into the sql window (the one saying "SELECT FROM"). You will get an error message saying that your code can't be displayed. Ignore it. Save your view. You can connect it to your Access database the same way you would connect a table.
Solution 2:
Use a SQL-Passthrough query in Access.
This is a bit complicated to explain, because almost every Access version has a slightly different menu. I'll explain it for Access 2007.
Create a new query. Close the "add table" window. Choose "Pass-Through" from the design menu (I don't know exactly if the menu label of the english version is "design". In my version it says "Entwurf"). Open the properties window. Insert the correct ODBC string. The easiest way to get an ODBC-string is to use one from an existing ODBC-table. Go to the VBA immediate window (Ctrl + G) and write ?CurrentDb.TableDefs("YourTable").Connect (instead of YourTable you have to insert the name of your ODBC-table). Press Return. You should get something like
ODBC;DSN=YourConnection;Description=IAmAnODBCConnection;APP=2007 Microsoft Office system;DATABASE=YourDatabase
Copy this string into the ODBC property of your query. Be sure the option "returns records" is set to "Yes". Copy you SQL into the query and save it.
Solution 3:
Convert your SQL Server syntax to Access syntax. Before doing this, you have to connect every table which is used in the query. I can't test my syntax conversion, but this should work:
PARAMETERS data DateTime = #2013-12-31#;
SELECT
RelCliSFN.CdCrt,
MC5.Nome "NomeCarteira",
MC5.CGC "CNPJCarteira",
player_adm.NomeCurto "Administrador",
RelCliSFN.Cliente,
CE5.Nome "NomeCliente",
CE5.CPFCGC "CPF/CNPJCliente",
VigRelCliSFN.DtIni,
VigRelCliSFN.DtFim
FROM
RelCliSFN
Inner JOIN MC5 ON MC5.Carteira = RelCliSFN.CdCrt
INNER JOIN MC5Auxiliar ON MC5.Carteira = MC5Auxiliar.Carteira
Inner Join VigRelCliSFN ON RelCliSFN.IdRelCliSFN = VigRelCliSFN.IdRelCliSFN
Inner Join CE5 ON CE5.Cliente=RelCliSFN.Cliente
LEFT OUTER JOIN PlayAdmxMC5 ON MC5.Carteira = PlayAdmxMC5.CdCrt AND PlayAdmxMC5.DtIniVig =
(SELECT MAX(DtIniVig) FROM PlayAdmxMC5 WHERE MC5.Carteira = CdCrt AND DtIniVig < MC5.DataAtual)
INNER JOIN Player player_adm ON PlayAdmxMC5.IdPlayAdm = player_adm.ID
WHERE
((VigRelCliSFN.DtIni <= [data])
and ((VigRelCliSFN.DtFim >= [data]) or (VigRelCliSFN.DtFim is null)))
and MC5.CGC <> 0
and CE5.Assessor not in (17, 99)
and CE5.CPFCGC <>0
and MC5.TipoCarteira <> 4
Well I don't know if Access can handle the equation of PlayAdmxMC5.DtIniVig = (Subquery). If it doesn't work, you should create a new query containing only the subquery and then connect it to this query.
MAIN CODE I am using
SELECT dbo_RelCliSFN.CdCrt, dbo_MC5.Nome AS NomeCarteira, dbo_MC5.CGC AS CNPJCarteira, dbo_RelCliSFN.Cliente, dbo_CE5.Nome AS NomeCliente, dbo_CE5.CPFCGC AS [CPF/CNPJCliente], dbo_VigRelCliSFN.DtIni, dbo_VigRelCliSFN.DtFim
FROM ((((dbo_RelCliSFN INNER JOIN dbo_CE5 ON dbo_RelCliSFN.Cliente = dbo_CE5.Cliente) INNER JOIN dbo_MC5 ON dbo_RelCliSFN.CdCrt = dbo_MC5.Carteira) INNER JOIN dbo_MC5Auxiliar ON dbo_MC5.Carteira = dbo_MC5Auxiliar.Carteira) INNER JOIN dbo_VigRelCliSFN ON dbo_RelCliSFN.IdRelCliSFN = dbo_VigRelCliSFN.IdRelCliSFN) LEFT JOIN Query1 ON dbo_MC5.Carteira = Query1.CdCrt
GROUP BY dbo_RelCliSFN.CdCrt, dbo_MC5.Nome, dbo_MC5.CGC, dbo_RelCliSFN.Cliente, dbo_CE5.Nome, dbo_CE5.CPFCGC, dbo_VigRelCliSFN.DtIni, dbo_VigRelCliSFN.DtFim, dbo_MC5.TipoCarteira, dbo_CE5.Assessor
HAVING (((dbo_RelCliSFN.CdCrt)=802) AND ((dbo_MC5.CGC)<>0) AND ((dbo_CE5.CPFCGC)<>0) AND ((dbo_VigRelCliSFN.DtIni)<=#12/31/2013#) AND ((dbo_VigRelCliSFN.DtFim)>=#12/31/2013# Or (dbo_VigRelCliSFN.DtFim) Is Null) AND ((dbo_MC5.TipoCarteira)<>4) AND ((dbo_CE5.Assessor) Not In (17.19)));

Convert TSQL Query To Access

I like to covert this query to Access 2007.
Every time I try to run it, I get a Syntax Error Missing operator in query Expression.
I appreciate any help
SELECT
u.UserID,
u.FirstName,
u.LastName,
u.Username,
u.Email,
u.DisplayName,
upd.TypeOfAccess,
upd.kusfCompanyCode FROM dbo.dnn_Users AS u INNER JOIN
dbo.dnn_UserRoles AS ur ON u.UserID = ur.UserID INNER JOIN
dbo.dnn_Roles AS r ON ur.RoleID = r.RoleID AND (r.RoleName = N'KUSF Agent' OR r.RoleName = N'KUSF Company With Agent' OR r.RoleName = N'KUSF Company Without Agent') LEFT OUTER JOIN
(SELECT
up.UserID,
MAX(CASE WHEN ppd.PropertyName = 'TypeOfAccess' THEN up.PropertyValue ELSE '' END) AS TypeOfAccess,
MAX(CASE WHEN ppd.PropertyName = 'kusf CompanyCode' THEN up.PropertyValue ELSE '' END) AS kusfCompanyCode
FROM
dbo.dnn_UserProfile AS up INNER JOIN
dbo.dnn_ProfilePropertyDefinition AS ppd ON
up.PropertyDefinitionID = ppd.PropertyDefinitionID AND ppd.PortalID = 0
GROUP BY up.UserID) as upd on u.UserID = upd.UserID
Check out this set of rules while converting TSQL query to Access 2007 query as outlined in the post. Probably it will help to solve your issue.
Convert Microsoft Access (JET SQL) to SQL Server (T-SQL) Cheatsheet
A few "problems" I'm seeing right off the bat:
Access SQL doesn't support CASE. Since both your CASE statements are two-valued, use Iif(<condition>, <true_part>, <false_part>).
Access is very picky about having multiple joins set off in parentheses. Work "last to first", catching the last join in a set of parens (both table names--in this case your sub-select is one of them--the join between and the ON field(s)), then another closing paren after that, which opens just before the table name of the preceding join, &c. until you have all but the first table name (and first JOIN) enclosed in parens. (Don't be fooled though--this does not actually enforce an order of evaluation).
I think Access wants LEFT JOIN rather than LEFT OUTER JOIN, but this might not matter.
Access may not support the "force to Unicode" N'string' operator. I've never used it, but won't actually swear that it's wrong (in context).
Access prefers double quotes to set off strings, rather than single. It usually accepts single quotes, though.
This may not solve your problem, but it may get you headed in the right direction.

Query on 3 tables

I've three tables in this mode:
Time1 with column "Data" in format gg/mm/aaaa
Manual with columns "valMan" and "dataora" same format.
Automatic with columns "valAuto" and "dataora" same format.
I must find values "valAuto" from table Automatic where Data.Time1 is = dataora.Automatic and if the value is null I take this value from valMan.Manual in the same Data.Time1 = dataora.Manual
In access sql or vb for access.
Is very important for me... Thank you a lot!!!
For MS Access you can try Iif and IsNull
SELECT Time1.Data,
IIf(IsNull([valAuto]),[valMan],[valAuto]) AS Expr1
FROM (Time1 LEFT JOIN Automatic ON Time1.Data = Automatic.dataora) LEFT JOIN
Manual ON Time1.Data = Manual.dataora;
or
Nz
SELECT Time1.Data,
Nz([valAuto],[valMan]) AS Expr1
FROM (Time1 LEFT JOIN Automatic ON Time1.Data = Automatic.dataora) LEFT JOIN
Manual ON Time1.Data = Manual.dataora;
Don't know about access, but this should do it in MS SQL Server
SELECT
ISNULL(a.valAuto, m.valMan) AS whatIWant
FROM
Automatic a
INNER JOIN Time1 t ON a.dataora = t.Data
INNER JOIN Manual m ON t.Data = m.dataora
The ISNULL command replaces valAuto with valMan if valAuto is null.

Subselect a Summed col in Oracle

this is an attempted fix to a crystal reports use of 2 sub reports!
I have a query that joins 3 tables, and I wanted to use a pair of sub selects that bring in the same new table.
Here is the first of the two columns in script:
SELECT ea."LOC_ID", lo."DESCR", ea."PEGSTRIP", ea."ENTITY_OWNER"
, ea."PCT_OWNERSHIP", ea."BEG_BAL", ea."ADDITIONS", ea."DISPOSITIONS"
, ea."EXPLANATION", ea."END_BAL", ea."NUM_SHARES", ea."PAR_VALUE"
, ag."DESCR", ea."EOY", ea."FAKEPEGSTRIP",
(select sum(htb.END_FNC_CUR_US_GAAP)
from EQUITY_ACCOUNTS ea , HYPERION_TRIAL_BALANCE htb
where
htb.PEGSTRIP = ea.PEGSTRIP and
htb.PRD_NBR = 0 and
htb.LOC_ID = ea.LOC_ID and
htb.PRD_YY = ea.EOY
) firstHyp
FROM ("TAXPALL"."ACCOUNT_GROUPING" ag
INNER JOIN "TAXP"."EQUITY_ACCOUNTS" ea
ON (ag."ACCT_ID"=ea."PEGSTRIP") AND (ag."EOY"=ea."EOY"))
INNER JOIN "TAXP"."LOCATION" lo ON ea."LOC_ID"=lo."LOC_ID"
WHERE ea."EOY"=2009
ORDER BY ea."LOC_ID", ea."PEGSTRIP"
When this delivers the dataset the value of "firstHyp" fails to change by pegstrip value. It returns a single total for the join and fails to put the proper by value by pegstrip.
I thought that the where clause would have picked up the joins line by line.
I don't do Oracle syntax often so what am I missing here?
TIA
Your SQL is equivilent to the following:
SELECT ea."LOC_ID", lo."DESCR", ea."PEGSTRIP",
ea."ENTITY_OWNER" , ea."PCT_OWNERSHIP",
ea."BEG_BAL", ea."ADDITIONS", ea."DISPOSITIONS" ,
ea."EXPLANATION", ea."END_BAL", ea."NUM_SHARES",
ea."PAR_VALUE" , ag."DESCR", ea."EOY", ea."FAKEPEGSTRIP",
(select sum(htb.END_FNC_CUR_US_GAAP)
from EQUITY_ACCOUNTS iea
Join HYPERION_TRIAL_BALANCE htb
On htb.PEGSTRIP = iea.PEGSTRIP
and htb.LOC_ID = iea.LOC_ID
and htb.PRD_YY = iea.EOY
where htb.PRD_NBR = 0 ) firstHyp
FROM "TAXPALL"."ACCOUNT_GROUPING" ag
JOIN "TAXP"."EQUITY_ACCOUNTS" ea
ON ag."ACCT_ID"=ea."PEGSTRIP"
AND ag."EOY"=ea."EOY"
JOIN "TAXP"."LOCATION" lo
ON ea."LOC_ID"=lo."LOC_ID"
WHERE ea."EOY"=2009
ORDER BY ea."LOC_ID", ea."PEGSTRIP"
Notice that the subquery that generates firstHyp is not in any way dependant on the tables in the outer query... It is therefore not a Correllated SubQuery... meaning that the value it generates will NOT be different for each row in the outer query's resultset, it will be the same for every row. You need to somehow put something in the subquery that makes it dependant on the value of some row in the outer query so that it will become a correllated subquery and run over and over once for each outer row....
Also, you mention a pair of subselects, but I only see one. Where is the other one ?
Use:
SELECT ea.LOC_ID,
lo.DESCR,
ea.PEGSTRIP,
ea.ENTITY_OWNER,
ea.PCT_OWNERSHIP,
ea.BEG_BAL,
ea.ADDITIONS,
ea.DISPOSITIONS,
ea.EXPLANATION,
ea.END_BAL,
ea.NUM_SHARES,
ea.PAR_VALUE,
ag.DESCR,
ea.EOY,
ea.FAKEPEGSTRIP,
NVL(SUM(htb.END_FNC_CUR_US_GAAP), 0) AS firstHyp
FROM TAXPALL.ACCOUNT_GROUPING ag
JOIN TAXP.EQUITY_ACCOUNTS ea ON ea.PEGSTRIP = ag.ACCT_ID
AND ea.EOY = ag.EOY
AND ea.EOY = 2009
JOIN TAXP.LOCATION lo ON lo.LOC_ID = ea.LOC_ID
LEFT JOIN HYPERION_TRIAL_BALANCE htb ON htb.PEGSTRIP = ea.PEGSTRIP
AND htb.LOC_ID = ea.LOC_ID
AND htb.PRD_YY = ea.EOY
AND htb.PRD_NBR = 0
GROUP BY ea.LOC_ID,
lo.DESCR,
ea.PEGSTRIP,
ea.ENTITY_OWNER,
ea.PCT_OWNERSHIP,
ea.BEG_BAL,
ea.ADDITIONS,
ea.DISPOSITIONS,
ea.EXPLANATION,
ea.END_BAL,
ea.NUM_SHARES,
ea.PAR_VALUE,
ag.DESCR,
ea.EOY,
ea.FAKEPEGSTRIP,
ORDER BY ea.LOC_ID, ea.PEGSTRIP
I agree with Charles Bretana's assessment that the original SELECT in the SELECT clause was not correlated, which is why the value never changed per row. But the sub SELECT used the EQUITY_ACCOUNTS table, which is the basis for the main query. So I removed the join, and incorporated the HYPERION_TRIAL_BALANCE table into the main query, using a LEFT JOIN. I wrapped the SUM in an NVL rather than COALESCE because I didn't catch what version of Oracle this is for.