Linked Server in SQL Server 2008 - sql

Newbie. Be gentle (or parental)
I have a query that I'm trying to build for a report. From instance AWDATA (SQL Server 2008), I have a linked server GGIAPP01 (which contains an ACCPAC database).
When I run the following, with lines commented out, all is well.
When I uncomment, I get no argument, the query runs, BW_AK.NR_RECHNUNG, BW_AP.ID, BW_AS.POS_NR are returned as NULL.
Also BW_AUFTR_KOPF is one to many BW_AUFTR_POS, and BW_AUFTR_POS is one to many BW_AUFTR_STKL, but the record count remains the same regardless.
I suspect the first (BW) join is the culprit, but I'm not sure how to verify exactly. Without the CAST, I get a type mismatch, as IDINVC is char(22) and NR_RECHNUNG is int.
Any feedback is appreciated. This is a new domain for me!
Thank you,
Matt
declare #FiscalPeriod integer = 03, #FiscalYear integer = 2014
select
AROBP.IDINVC, AROBP.AMTPAYMTC, AROBP.TRANSTYPE, AROBP.TRXTYPE,
AROBP.FISCPER, AROBP.FISCYR, AROBP.DATEBTCH, AROBP.IDCUST,
ARCUS.NAMECUST,
ARIBH.TEXTTRX, ARIBH.DATEINVC, ARIBH.AMTINVCTOT,
ARSAP.NAMEEMPL,
-- BW_AK.NR_RECHNUNG,
-- BW_AP.ID,
-- BW_AS.POS_NR
from GGIAPP01.GGI.dbo.AROBP AROBP
left join GGIAPP01.GGI.dbo.ARCUS ARCUS on AROBP.IDCUST = ARCUS.IDCUST
left join GGIAPP01.GGI.dbo.ARIBH ARIBH on AROBP.IDINVC = ARIBH.IDINVC
left join GGIAPP01.GGI.dbo.ARSAP ARSAP on ARCUS.CODESLSP1 = ARSAP.CODESLSP
--left join GGIMAIN.SYSADM.BW_AUFTR_KOPF BW_AK on AROBP.IDINVC = CAST(BW_AK.NR_RECHNUNG as
--varchar)
--left join GGIMAIN.SYSADM.BW_AUFTR_POS BW_AP on BW_AK.ID = BW_AP.ID
--left join GGIMAIN.SYSADM.BW_AUFTR_STKL BW_AS on BW_AP.ID = BW_AS.ID and BW_AP.POS_NR =
--BW_AS.POS_NR
where AROBP.IDINVC NOT LIKE 'PY%'
AND AROBP.FISCPER = #FiscalPeriod
AND AROBP.FISCYR = #FiscalYear
order by AROBP.IDINVC, ARSAP.NAMEEMPL, AROBP.IDCUST

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)));

ORA-00918: column ambigously defined, using DB Link

When I execute the query below I get the following error message :
ORA-00918: column ambigously defined
ORA-02063: preceding line from ABC
Query:
SELECT
dos.*,
cmd.*,
cmd_r.*,
adr_inc.*,
adr_veh.*,
loc.*,
fou_d.*,
fou_r.*, --Works if I comment this line
mot.*
FROM
DOSSIERS#ABC dos
LEFT JOIN CMDS#ABC cmd ON cmd.DOS_CODE_ID = dos.dos_code_id
LEFT JOIN CMDS_RECCSTR#ABC cmd_r ON cmd_r.DOS_CODE_ID = dos.DOS_CODE_ID AND cmd_r.CMD_CODE_ID = cmd.CMD_CODE_ID AND cmd_r.CMD_DT_CREAT = cmd.CMD_DT_CREAT
LEFT JOIN HISTO_ADR#ABC adr_inc ON adr_inc.DOS_CODE_ID = dos.DOS_CODE_ID
LEFT JOIN HISTO_ADR#ABC adr_veh ON adr_veh.DOS_CODE_ID = dos.DOS_CODE_ID
LEFT JOIN LOC#ABC loc ON dos.DOS_CODE_ID = loc.DOS_CODE_ID
LEFT JOIN FOURNISS#ABC fou_d ON fou_d.PAY_CODE_ID = loc.PAY_CODE_ID_D AND fou_d.FOU_CODE_ID = loc.FOU_CODE_ID_D
LEFT JOIN FOURNISS#ABC fou_r ON fou_r.PAY_CODE_ID = loc.PAY_CODE_ID_R AND fou_r.FOU_CODE_ID = loc.FOU_CODE_ID_R
LEFT JOIN REF_MOT#ABC mot ON mot.RMR_CODE_ID = cmd_r.RMR_CODE_ID
WHERE
dos.REF_EXT = 'XXXXXXX'
If I comment fou_r.* in SELECT it works.
The following queries don't work neither:
SELECT *
FROM ... ;
SELECT (SELECT count(xxx) FROM ...)
FROM ...;
I looked at similar issues on SO but they were all using complex queries or was using many SELECT inside WHERE. Mine is simple that is why I don't understand what could be wrong.
Current Database: Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
Target Database (refers to db link ABC target): Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
Client: Toad for Oracle 9.7.2.5
You seem to be hitting bug 13589271. I can't share details from MOS, but there isn't much to share anyway. It's related to the remote table having a column with a 30-character name though, as you have in your remote FOURNIUSS table.
Unfortunately simply aliasing the column in your query, like this:
fou_d.COLUMN_WITH_30_CHARACTERS_NAME alias_a,
fou_r.COLUMN_WITH_30_CHARACTERS_NAME alias_b,
... doesn't help and still gets the same error, as the alias is applied by the local database and the problem seems to be during the remote access. What does seem to work is using an in-line view to apply a column alias before the join:
...
LEFT JOIN LOC#ABC loc ON dos.DOS_CODE_ID = loc.DOS_CODE_ID
LEFT JOIN (
SELECT PAY_CODE_ID, FOU_CODE_ID, COLUMN_WITH_30_CHARACTERS_NAME alias_a FROM FOURNISS#ABC
) fou_d ON fou_d.PAY_CODE_ID = loc.PAY_CODE_ID_D AND fou_d.FOU_CODE_ID = loc.FOU_CODE_ID_D
LEFT JOIN (
SELECT PAY_CODE_ID, FOU_CODE_ID, COLUMN_WITH_30_CHARACTERS_NAME alias_b FROM FOURNISS#ABC
) fou_r ON fou_r.PAY_CODE_ID = loc.PAY_CODE_ID_R AND fou_r.FOU_CODE_ID = loc.FOU_CODE_ID_R
LEFT JOIN REF_MOT#ABC mot ON mot.RMR_CODE_ID = cmd_r.RMR_CODE_ID
...
This even works if you give the column the same alias in both inline views. The downside is that you have to explicitly list all of the columns from the table (or at least those you're interested in) in order to be able to apply the alias to the problematic one, but having done so you can still use fou_d.* and fou_r.* in the outer select list.
I don't have an 11.2.0.2 database but I've run this successfully in an 11.2.0.3 database which still showed the ORA-00918 error from your original code. It's possible something else in 11.2.0.2 will stop this workaround being effective, of course. I don't see the original problem in 11.2.0.4 at all, so upgrading to that terminal patch release might be a better long-term solution.
Using * is generally considered a bad practice anyway though, not least because you're going to get a lot of duplicated columns from the joins (lots of dos_code_id in each row, for example); but you're also likely to be getting other data you don't really want, and anything that consumes this result set will have to assume the column order is always the same in those tables - any variation, or later addition or removal of a column, will cause problems.

SQL Query for all systemusers who's organisationunits has a datevalue < ... with pivot table in between

I have 3 tables,
SystemUsers
OrganisationalUnits
UserOrganisationUnits - Pivot with UserId/OrganisationUnitId foreign keys
All tables have an Active bit column and the OrganisationalUnit table has a CoveredTill datetime column.
I want a list of all UserOrganisationUnits where OrganisationalUnit "CoveredTill" is < x (value doesn't matter as will be set in clr) date and all tables records are active.
So far I've only managed to get unique users from my query so any advice would be much appreciated.
SELECT
SystemUsers.DisplayName, SystemUsers.Email,
OrganisationalUnits.Description, OrganisationalUnits.CoveredTill,
OrganisationalUnits.Id, OrganisationalUnits.ParentId, OrganisationalUnits.TypeId
FROM
SystemUsers
RIGHT OUTER JOIN
OrganisationalUnits ON SystemUsers.Id = OrganisationalUnits.Id
INNER JOIN
UserOrganisationUnits ON SystemUsers.Id = UserOrganisationUnits.Id
WHERE
(OrganisationalUnits.Active = 1)
AND (SystemUsers.Active = 1)
AND (UserOrganisationUnits.Active = 1)
AND (OrganisationalUnits.CoveredTill < '2017-03-31 00:00:00.000')
I randomly set the date as the above since I manually set the covered till date as "2015-03-31 00:00:00.000" on all OrganisationalUnits "CoveredTill" columns.
My aim is to have a single sql query string which I can use in my clr stored procedure to create a list of all users who need to be emailed because there organisational unit is no longer covered and for said email to include which organisational unit hence why just having a unique list of users isn't sufficient.
I already have the email code so it's just the query I'm having issues with.
Edit:-
I had first approached this as needing 3 separate queries which I guess after a bit more testing I'll have to revisit unless someone can spot what I'm doing wrong with the above query?
Edit 2:-
After working through the issue with sarin and preparing to provide him a sql db/query copy I found that some of the joins were pointing towards the wrong ID fields (automatically created from different panes so always be wary of anything they create) so below I've included the final solution. (Which includes a couple extra fields I decided might be useful).
SELECT OrganisationalUnits.Description, OrganisationalUnits.CoveredTill, SystemUsers.DisplayName, SystemUsers.Email,
UserOrganisationUnits.LastVisited AS UOULastVisited, SystemUsers.LastVisited AS SULastVisited
FROM UserOrganisationUnits INNER JOIN
OrganisationalUnits ON UserOrganisationUnits.OrganisationUnitId = OrganisationalUnits.Id INNER JOIN
SystemUsers ON UserOrganisationUnits.UserId = SystemUsers.Id
WHERE (OrganisationalUnits.Active = 1) AND (SystemUsers.Active = 1) AND (UserOrganisationUnits.Active = 1) AND
(OrganisationalUnits.CoveredTill < '2017-03-31 00:00:00.000')
Performing a Right\left join before you do an inner join can give you unexpected results as it may produce nulls and your inner join will then attempt to filter them out. I'm not entirely clear about the relationships between the tables but can you turn them all into INNER JOINS to get the same list and produce you a similar result based on your expected outcome?
"My aim is.... to create a list of all users who need to be emailed because there organisational unit is no longer covered"
UPDATED:
SELECT
SystemUsers.DisplayName, SystemUsers.Email,
OrganisationalUnits.Description, OrganisationalUnits.CoveredTill,
OrganisationalUnits.Id, OrganisationalUnits.ParentId, OrganisationalUnits.TypeId
FROM
UserOrganisationUnits
INNER JOIN SystemUsers ON SystemUsers.Id = UserOrganisationUnits.Id
AND (SystemUsers.Active = 1)
INNER JOIN OrganisationalUnits ON OrganisationalUnits.Id = SystemUsers.Id
AND OrganisationalUnits.Active = 1
AND OrganisationalUnits.CoveredTill < '2017-03-31 00:00:00.000'
WHERE UserOrganisationUnits.Active = 1

SQL Server returns empty fields

I have a select script that runs 3 times a day in a 2005 SQL Server installation, a few times the return table has contained expected number of rows but without any values. The integer and date fields have zeros and the others are simply blank.
Since the problem occurs very rarely there is no way to supervise the database when the script runs and haven't been able to replicate the issue. My thought is that some other update in the database is causing the problem. Does anyone know about this problem?
Here is the script
SELECT DISTINCT
URL.Line,
RTrim(URL.DescriptionNote) AS [DescriptionNote],
SA1.Name AS [Name1],
SP1.Designation AS [Designation1],
SA2.Name [Name2],
SP2.Designation AS [Designation2],
RL.DistanceMeters,
dbo.RouteLinkTransportModeDesc(URL.TransportModeTypeNumber) AS TransportMode,
URL.THM,
URL.FirstWorkedDate,
URL.LastWorkedDate
FROM #RequiredRouteLink URL
INNER JOIN StopPoint AS SP1
ON SP1.JourneyPatternPointGid = URL.StartsAtPointGid
INNER JOIN StopArea AS SA1
ON SP1.IsPartOfStopAreaVersionId = SA1.VersionId
INNER JOIN StopPoint AS SP2
ON SP2.JourneyPatternPointGid = URL.EndsAtPointGid
INNER JOIN StopArea AS SA2
ON SP2.IsPartOfStopAreaVersionId = SA2.VersionId
LEFT JOIN verRouteLink AS RL
ON RL.StartsAtPointGid = URL.StartsAtPointGid
AND RL.EndsAtPointGid = URL.EndsAtPointGid
AND URL.TransportModeTypeNumber = RL.TransportModeTypeNumber
WHERE URL.StartsAtPointGid <> URL.EndsAtPointGid
AND (RL.EndsAtPointGid IS NULL OR RL.DistanceMeters = 0 OR RL.DistanceMeters IS NULL)
AND RL.[DeletedDateTime] IS NULL
ORDER BY FirstWorkedDate, THM, TransportMode, Line, DescriptionNote
I'm sure it is a data issue. The reason you are getting blank fields is most likely the LEFT JOIN.
You have 4 INNER JOINs, any one of which could cause you to have an empty result set. If one or more of those don't find a match, you have no results.
However, your LEFT JOIN means you will at least get the list of URL.Line, which is why you had the expected number of rows most likely.
Can you run a low level SQL trace - filtering it as much as possible to reduce the load of the trace [e.g., by application, etc.]