How to access separate database from SQL Server stored procedure - sql

I am trying to run the below code but run into the error:
Multi-part Identifier could not be bound
I think it is due to trying to access a database table from a separate database but it is on the same server. Any ideas?
SELECT DISTINCT
#ActiveStudents2 = COUNT([ActivityHistory].[dbo].[tblActivityCounts].[id])
FROM
dbo.tblSchools
INNER JOIN
dbo.tblStudentSchool ON dbo.tblSchools.schoolid = dbo.tblStudentSchool.schoolid
INNER JOIN
dbo.tblStudentPersonal ON dbo.tblStudentSchool.id = dbo.tblStudentPersonal.id
WHERE
dbo.tblStudentSchool.schoolid IN (#tempschoolid)
AND tblStudentSchool.graduationyear IN (SELECT Items
FROM FN_Split(#gradyears, ','))
AND ([ActivityHistory].[dbo].[tblActivityCounts].[datetimechanged] >= #datefrom
AND [ActivityHistory].[dbo].[tblActivityCounts].[datetimechanged] <= #dateto)
The error occurs when I try to access the tblActivityCounts table in the Activity History database which is a separate database. I even try running this as the sa and it doesn't work. There aren't any spelling errors. Any help is appreciated. Thank you!

You are not joining on ActivityHistory table. That's why the query doesn't know from where to access tblActivityCounts table.

As Aleem said, you're not joining in the other table. I'd also recommend taking advantage of table aliases to make your code just a bit more readable... Makes it much easier to figure out what you were doing when you come back to it later.
Depending on how tblActivityCounts relates to the other tables, you would do something like this:
SELECT #ActiveStudents2 = COUNT(ActivityHistory.dbo.tblActivityCounts.id)
FROM dbo.tblSchools as Schools
INNER JOIN dbo.tblStudentSchool as Students
ON Schools.schoolid = Students.schoolid
INNER JOIN dbo.tblStudentPersonal as Personel
ON Students.id = Personel.id
INNER JOIN ActivityHistory.dbo.tblActivityCounts as Activity
ON Activity.studentid = Students.id -- Depending on how tblActivityCounts relates to the other tables
WHERE Students.schoolid IN (#tempschoolid)
AND tblStudentSchool.graduationyear IN (SELECT Items FROM FN_Split(#gradyears, ','))
AND Activity.datetimechanged >= #datefrom
AND Activity.datetimechanged <= #dateto

Your query is wrong. This line:
SELECT DISTINCT
#ActiveStudents2 =
COUNT([ActivityHistory].[dbo].[tblActivityCounts].[id])
Will retrieve all Ids from the tblActivityCounts table and count them, but has no reference in the rest of your query. You have to JOIN with this table and reference it to make your count. Also, I would recommend you use aliases.
Something like this:
SELECT DISTINCT
#ActiveStudents2 = COUNT(ah.[id])
FROM dbo.tblSchools s
INNER JOIN dbo.tblStudentSchool ss ON s.schoolid = ss.schoolid
INNER JOIN dbo.tblStudentPersonal sp ON s.id = sp.id
INNER JOIN [ActivityHistory].[dbo].[tblActivityCounts] ah ON s.acIdentifier = ah.acIdentifier
WHERE ss.schoolid IN (#tempschoolid)
AND ss.graduationyear IN (SELECT Items
FROM FN_Split(#gradyears, ','))
AND ([ActivityHistory].[dbo].[tblActivityCounts].[datetimechanged] >= #datefrom
AND [ActivityHistory].[dbo].[tblActivityCounts].[datetimechanged] <= #dateto)

Related

How to fix SQL query to Left Join a subquery with Where clause?

I'm new to SQL and I'm not certain why I am getting this error. I am trying to left join a sub-query to another query in sql developer.
This is the first query,
SELECT DISTINCT
tl.species,
ag.age
FROM
age_list ag,
tree_list tl
WHERE
ag.tree_id = tl.tree_id
And then the sub-query I would like to left join where the tree_id = tree_number is,
SELECT DISTINCT
sl.tree_spon,
sl.tree_number
FROM spon_list sl
WHERE
sl.tree_spon < 10
When trying to do this I've tried to use,
SELECT DISTINCT
tl.species,
ag.age,
q1.tree_spon
FROM
age_list ag,
tree_list tl
LEFT OUTER JOIN (SELECT DISTINCT
sl.tree_spon,
sl.tree_number
FROM spon_list sl
WHERE sl.tree_spon < 10) q1 on q1.tree_number = tree_list.tree_id
WHERE
ag.tree_id = tl.tree_id
Whatever I change in terms of the alias' for the columns and tables I always get the error, "ORA-00904: invalid identifier error", and that "tree_list.tree_id is invalid identifier", though separately the queries run fine.
Can anyone help, is it an issue with both queries joining on the tl.tree_id?
You can use the ANSI join syntax throughout (rather than mixing in legacy comma joins), joining on ag.tree_id = sl.tree_number (or tl.tree_id = sl.tree_number but they're both equal given the previous join) and putting the filter on sl.tree_spon < 10 into the ON clause as well:
SELECT DISTINCT
tl.species,
ag.age,
sl.tree_spon,
sl.tree_number
FROM age_list ag
INNER JOIN tree_list tl
ON (ag.tree_id = tl.tree_id)
LEFT OUTER JOIN spon_list sl
ON (ag.tree_id = sl.tree_number AND sl.tree_spon < 10)
Change tree_list.tree_id to tl.tree_id

SQL Using join but without on Condition

I am looking for someone to help by updating this sql statement, as I want to join two tables but without using " ON AD.[UID] = UI.[UID] " ?
SELECT AD.[AdsID] ,AD.[UID] ,AD.[Section] ,AD.[Category] ,AD.[Country] ,AD.[State] ,AD.[City] ,SUBSTRING([AdsTit],1,30)+'...' as AdsTit ,SUBSTRING([AdsDesc],1,85) as AdsDesc ,AD.[AdsPrice] ,AD.[Img1] ,AD.[Currency] ,AD.[Section] ,AD.[Currency] ,AD.[AdsDate] ,AD.[approvAds] ,UI.[approv]
FROM [ads] as AD JOIN UserInfo as UI ON AD.[UID] = UI.[UID]
where AD.[Country] = #Location AND AD.[approvAds]= 'Y' AND UI.[approv]='Y'
ORDER BY [AdsDate] DESC
You can move condition from 'on' to 'where', it works like inner join
SELECT AD.[AdsID] ,AD.[UID] ,AD.[Section] ,AD.[Category] ,AD.[Country] ,AD.[State] ,AD.[City] ,SUBSTRING([AdsTit],1,30)+'...' as AdsTit ,SUBSTRING([AdsDesc],1,85) as AdsDesc ,AD.[AdsPrice] ,AD.[Img1] ,AD.[Currency] ,AD.[Section] ,AD.[Currency] ,AD.[AdsDate] ,AD.[approvAds] ,UI.[approv]
FROM [ads] as AD, UserInfo as UI
where AD.[UID] = UI.[UID]
and AD.[Country] = #Location AND AD.[approvAds]= 'Y' AND UI.[approv]='Y'
ORDER BY [AdsDate] DESC
You can use the USING keyword instead of ON in your SQL query or use a natural join, which compares all the common columns in two tables itself without the on condition.
Query for your tables like this:
select AD.column1, AD.column2, UI.column1, UI.column2........
from ads AD join userinfo UI using(UID)
where AD.country='location' and AD.ApprovAds='y' and UI.approv='y'
order by Ads(date) desc
Or
select AD.column1, AD.column2, UI.column1, UI.column2........
from ads AD natural join userinfo UI
where AD.country='location' and AD.ApprovAds='y' and UI.approv='y'
order by Ads(date) desc
you want a cross join, don't recommend doing this as the performance is better on a join with a conditional statement.
That being said here is how you do it:
SELECT A.*, B.*
FROM A CROSS JOIN B
WHERE A.Id = B.AId
Just put the tables you need in place of A and B statements

Using COALESCE with JOIN on a different database column

Trying to populate the location column of a query and was hoping that the use of the COALESCE function would help me get what I want.
SELECT OrderItem.Code AS ItemCode, MAX(COALESCE(OrderItem.Location, [Picklist].[dbo].[ItemData].InventoryLocation)) AS Location, SUM(OrderItem.Quantity) AS Quantity, MAX(Store.StoreName) AS Store
FROM OrderItem
INNER JOIN [Order] ON OrderItem.OrderID = [Order].OrderID
INNER JOIN [Store] ON [Order].StoreID = [Store].StoreID
LEFT JOIN [AmazonOrder] ON [AmazonOrder].OrderID = [Order].OrderID
JOIN [Picklist].[dbo].[ItemData] ON [Picklist].[dbo].[ItemData].[InventoryNumber] = [OrderItem].[Code]
WHERE (CASE WHEN [Order].[LocalStatus] = 'Recently Downloaded' AND [AmazonOrder].FulfillmentChannel = 2 THEN 1
WHEN [Order].[LocalStatus] = 'Recently Downloaded' AND [Store].StoreName != 'Amazon' THEN 1 ELSE 0 END ) = 1
GROUP BY OrderItem.Code
ORDER BY ItemCode
There will not be a location when the Store is Amazon so I need to Join on another table in another database. I don't believe I'm using this correctly. Also I do get the right Location results returned if I use :
SELECT InventoryLocation From [Picklist].[dbo].[ItemData] WHERE InventoryNumber = 'L1201-2W-EA'
Perhaps this is more like the query that you want:
SELECT oi.Code AS ItemCode, COALESCE(oi.Location, id.InventoryLocation) AS Location,
oi.Quantity, s.StoreName AS Store
FROM OrderItem oi INNER JOIN
[Order] o
ON oi.OrderID = o.OrderID INNER JOIN
[Store]
ON o.StoreID = s.StoreID LEFT JOIN
AmazonOrder ao
ON ao.OrderID = o.OrderID JOIN
[Picklist].[dbo].[ItemData] id
ON id.InventoryNumber = oi.[Code]
WHERE o.LocalStatus = 'Recently Downloaded' AND
(ao.FulfillmentChannel = 2 OR s.StoreName <> 'Amazon')
ORDER BY ItemCode
Here are the changes:
Removed the aggregation. It does not seem to be part of the question.
Introduced table aliases, so the query is easier to write and to read.
Simplified the logic in the where clause.
As the comment above says, the max seems somewhat strange, an arbitrary aggregation no doubt due to one of the joins bringing back more information than you might of expected.
Then the statement has a few issues:
The coalesce is using two fields, neither if which is in a left join, only the AmazonOrder is left joined, so that seems a bit strange, that would only work if the first field in the coalesce (OrderItem.Location) is nullable - which it might be, there is no schema posted.
The left join itself is an inner join in disguise at present - within the where clause you have given explicit conditions on a field from that table - AND [AmazonOrder].FulfillmentChannel = 2 - if the record was actually missing the left join would return null for that field, and the where clause would then drop it out of the results. If you want this to properly work as a left join, any condition on fields from that table must move into the join condition, or the where clause itself must allow for that field being null (explicitly or using a coalesce.)
SELECT OrderItem.Code AS Code,
CASE WHEN (LEN(ISNULL(MAX([OrderItem].[Location]),'')) = 1)
THEN MAX([OrderItem].[Location])
ELSE MAX([Picklist].[dbo].[ItemData].InventoryLocation)
END AS Location,
SUM(OrderItem.Quantity) AS Quantity,
MAX(Store.StoreName) AS Store
FROM OrderItem
INNER JOIN [Order] ON OrderItem.OrderID = [Order].OrderID
INNER JOIN [Store] ON [Order].StoreID = [Store].StoreID
LEFT JOIN [AmazonOrder] ON [AmazonOrder].OrderID = [Order].OrderID
LEFT JOIN [Picklist].[dbo].[ItemData] ON [Picklist].[dbo].[ItemData].[InventoryNumber] = [OrderItem].[Code] OR
[Picklist].[dbo].[ItemData].[MediaCreator] = [OrderItem].[Code]
WHERE [Order].LocalStatus = 'Recently Downloaded' AND (AmazonOrder.FulfillmentChannel = 2 OR Store.StoreName <> 'Amazon')
GROUP BY OrderItem.Code
ORDER BY OrderItem.Code
Decided to go with case statement on location column route because I could not get COALESCE to work for me. Schema, some not all data, at SQLFiddle.
I guess if someone gets COALESCE to work I'll change the answer?
#Gordon Linoff I used the re-written WHERE clause because it looked cleaner than using the CASE statement. It worked and guessed there was a simpler way to go about it but was more worried about getting COALESCE to work. As for the Aliases sometimes I like to use them but in this case since there was a lot of tables I like to code out what I'm actually working in. Just my preference .

Ambiguous outer join in MS Access

Trying to create an outer join on two other joined tables when recieving this error - I just dont see how to create two separate queries to make it work. Subqueries don't seem to work either, any help appreciated. I get errors for the below query, thanks.
SELECT
CardHeader.CardID, CardHeader.CardDescription, CardHeader.GloveSize,
CardHeader.GloveDescription, CardDetail.Bin, CardDetail.ItemID, Items.ItemDescription,
Items.VCatalogID, CardDetail.ChargeCode, CardDetail.Quantity, Items.Cost, CardColors.ColorID
FROM
((Items
INNER JOIN
(CardHeader INNER JOIN CardDetail ON CardHeader.CardID = CardDetail.CardID) ON Items.ItemID = CardDetail.ItemID)
LEFT JOIN
CardColors ON CardDetail.ItemID = CardColors.ItemID)
INNER JOIN
Colors ON CardColors.ColorID = Colors.ID
ORDER BY
CardHeader.CardID;
I tried the following which runs but asks for the following parameters (which it shouldnt)
CardHeader.ID, MainQry.CardID
SELECT
MainQry.ID, MainQry.CardDescription, MainQry.GloveSize,
MainQry.GloveDescription, MainQry.Bin, MainQry.ItemID,
MainQry.ItemDescription, MainQry.VCatalogID, MainQry.ChargeCode,
MainQry.Quantity, MainQry.Cost, SubQry.ColorID
FROM
(SELECT
CardHeader.ID, CardHeader.CardDescription, CardHeader.GloveSize,
CardHeader.GloveDescription, CardDetail.Bin,
CardDetail.ItemID, Items.ItemDescription, Items.VCatalogID,
CardDetail.ChargeCode, CardDetail.Quantity, Items.Cost
FROM
Items
INNER JOIN
(CardHeader
INNER JOIN
CardDetail ON CardHeader.CardID = CardDetail.CardID) ON Items.ItemID = CardDetail.ItemID
) AS MainQry
LEFT JOIN
(SELECT
CardColors.ItemID, CardColors.ColorID
FROM
CardColors
INNER JOIN
Colors ON CardColors.ColorID = Colors.ID) AS SubQry ON MainQry.ItemID = SubQry.ItemID
ORDER BY
MainQry.CardID;
The second SQL statement can be corrected by reference to the first statement and the error. The error is that both CardHeader.ID and MainQry.CardID are prompting for a parameter, which indicates that the inner statement should include CardHeader.CardID, rather than CardHeader.ID

Super Slow Query - sped up, but not perfect... Please help

I posted a query yesterday (see here) that was horrible (took over a minute to run, resulting in 18,215 records):
SELECT DISTINCT
dbo.contacts_link_emails.Email, dbo.contacts.ContactID, dbo.contacts.First AS ContactFirstName, dbo.contacts.Last AS ContactLastName, dbo.contacts.InstitutionID,
dbo.institutionswithzipcodesadditional.CountyID, dbo.institutionswithzipcodesadditional.StateID, dbo.institutionswithzipcodesadditional.DistrictID
FROM
dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_3
INNER JOIN
dbo.contacts
INNER JOIN
dbo.contacts_link_emails
ON dbo.contacts.ContactID = dbo.contacts_link_emails.ContactID
ON contacts_def_jobfunctions_3.JobID = dbo.contacts.JobTitle
INNER JOIN
dbo.institutionswithzipcodesadditional
ON dbo.contacts.InstitutionID = dbo.institutionswithzipcodesadditional.InstitutionID
LEFT OUTER JOIN
dbo.contacts_def_jobfunctions
INNER JOIN
dbo.contacts_link_jobfunctions
ON dbo.contacts_def_jobfunctions.JobID = dbo.contacts_link_jobfunctions.JobID
ON dbo.contacts.ContactID = dbo.contacts_link_jobfunctions.ContactID
WHERE
(dbo.contacts.JobTitle IN
(SELECT JobID
FROM dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_1
WHERE (ParentJobID <> '1841')))
AND
(dbo.contacts_link_emails.Email NOT IN
(SELECT EmailAddress
FROM dbo.newsletterremovelist))
OR
(dbo.contacts_link_jobfunctions.JobID IN
(SELECT JobID
FROM dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_2
WHERE (ParentJobID <> '1841')))
AND
(dbo.contacts_link_emails.Email NOT IN
(SELECT EmailAddress
FROM dbo.newsletterremovelist AS newsletterremovelist))
ORDER BY EMAIL
With a lot of coaching and research, I've tuned it up to the following:
SELECT contacts.ContactID,
contacts.InstitutionID,
contacts.First,
contacts.Last,
institutionswithzipcodesadditional.CountyID,
institutionswithzipcodesadditional.StateID,
institutionswithzipcodesadditional.DistrictID
FROM contacts
INNER JOIN contacts_link_emails ON
contacts.ContactID = contacts_link_emails.ContactID
INNER JOIN institutionswithzipcodesadditional ON
contacts.InstitutionID = institutionswithzipcodesadditional.InstitutionID
WHERE
(contacts.ContactID IN
(SELECT contacts_2.ContactID
FROM contacts AS contacts_2
INNER JOIN contacts_link_emails AS contacts_link_emails_2 ON
contacts_2.ContactID = contacts_link_emails_2.ContactID
LEFT OUTER JOIN contacts_def_jobfunctions ON
contacts_2.JobTitle = contacts_def_jobfunctions.JobID
RIGHT OUTER JOIN newsletterremovelist ON
contacts_link_emails_2.Email = newsletterremovelist.EmailAddress
WHERE (contacts_def_jobfunctions.ParentJobID <> 1841)
GROUP BY contacts_2.ContactID
UNION
SELECT contacts_1.ContactID
FROM contacts_link_jobfunctions
INNER JOIN contacts_def_jobfunctions AS contacts_def_jobfunctions_1 ON
contacts_link_jobfunctions.JobID = contacts_def_jobfunctions_1.JobID
AND contacts_def_jobfunctions_1.ParentJobID <> 1841
INNER JOIN contacts AS contacts_1 ON
contacts_link_jobfunctions.ContactID = contacts_1.ContactID
INNER JOIN contacts_link_emails AS contacts_link_emails_1 ON
contacts_link_emails_1.ContactID = contacts_1.ContactID
LEFT OUTER JOIN newsletterremovelist AS newsletterremovelist_1 ON
contacts_link_emails_1.Email = newsletterremovelist_1.EmailAddress
GROUP BY contacts_1.ContactID))
While this query is now super fast (about 3 seconds), I've blown part of the logic somewhere - it only returns 14,863 rows (instead of the 18,215 rows that I believe is accurate).
The results seem near correct. I'm working to discover what data might be missing in the result set.
Can you please coach me through whatever I've done wrong here?
Thanks,
Russell Schutte
The main problem with your original query was that you had two extra joins just to introduce duplicates and then a DISTINCT to get rid of them.
Use this:
SELECT cle.Email,
c.ContactID,
c.First AS ContactFirstName,
c.Last AS ContactLastName,
c.InstitutionID,
izip.CountyID,
izip.StateID,
izip.DistrictID
FROM dbo.contacts c
INNER JOIN
dbo.institutionswithzipcodesadditional izip
ON izip.InstitutionID = c.InstitutionID
INNER JOIN
dbo.contacts_link_emails cle
ON cle.ContactID = c.ContactID
WHERE cle.Email NOT IN
(
SELECT EmailAddress
FROM dbo.newsletterremovelist
)
AND EXISTS
(
SELECT NULL
FROM dbo.contacts_def_jobfunctions cdj
WHERE cdj.JobId = c.JobTitle
AND cdj.ParentJobId <> '1841'
UNION ALL
SELECT NULL
FROM dbo.contacts_link_jobfunctions clj
JOIN dbo.contacts_def_jobfunctions cdj
ON cdj.JobID = clj.JobID
WHERE clj.ContactID = c.ContactID
AND cdj.ParentJobId <> '1841'
)
ORDER BY
email
Create the following indexes:
newsletterremovelist (EmailAddress)
contacts_link_jobfunctions (ContactID, JobID)
contacts_def_jobfunctions (JobID)
Do you get the same results when you do:
SELECT count(*)
FROM
dbo.contacts_def_jobfunctions AS contacts_def_jobfunctions_3
INNER JOIN
dbo.contacts
INNER JOIN
dbo.contacts_link_emails
ON dbo.contacts.ContactID = dbo.contacts_link_emails.ContactID
ON contacts_def_jobfunctions_3.JobID = dbo.contacts.JobTitle
SELECT COUNT(*)
FROM
contacts
INNER JOIN contacts_link_jobfunctions
ON contacts.ContactID = contacts_link_jobfunctions.ContactID
INNER JOIN contacts_link_emails
ON contacts.ContactID = contacts_link_emails.ContactID
If so keep adding each join conditon on until you don't get the same results and you will see where your mistake was. If all the joins are the same, then look at the where clauses. But I will be surprised if it isn't in the first join because the syntax you have orginally won't even work on SQL Server and it is pretty nonstandard SQL and may have been incorrect all along but no one knew.
Alternatively, pick a few of the records that are returned in the orginal but not the revised. Track them through the tables one at a time to see if you can find why the second query filters them out.
I'm not directly sure what is wrong, but when I run in to this situation, the first thing I do is start removing variables.
So, comment out the where clause. How many rows are returned?
If you get back the 11,604 rows then you've isolated the problems to the joins. Work though the joins, commenting each one out (remove the associated columns too) and figure out how many rows are eliminated.
As you do this, aim to find what is causing the desired rows to be eliminated. Once isolated, consider the join differences between the first query and the second query.
In looking at the first query, you could probably just modify that to eliminate any INs and instead do a EXISTS instead.
Consider your indexes as well. Any thing in the where or join clauses should probably be indexed.