When I run select from linked SQL Server 2012 like this:
select A.*
from A, (select TOP 1 * from B) as B
where A.test in (B.col1, B.col2)
I only get 1 row from A though A has many rows. B here is parameters table with only 1 row.
A and B here is synonyms which point to tables on remote server.
We know that TOP without ORDER BY may produce non-deterministic results, but if we have only 1 row in table it must be OK. However, the MS SQL Server 2012 in case from question do his job very bad. To avoid such problem you have to write ORDER BY in nested table (B)! After that, query give right results. So, right query must be:
select A.*
from A, (select TOP 1 * from B ORDER BY <any field>) as B
where A.test in (B.col1, B.col2)
Take into account that SQL Server do well in case with local server but working differently in case of linked server.
In your given query, the join structure is considered a
CROSS JOIN
, so by adding a filter in the
WHERE
clause you are effectively changing the join criteria to an
INNER JOIN
following this join structure. Also everyone else who will maintain your code will be better off if you use the ANSI-92 SQL Standard.
Consider a query like this:
SELECT A.*
FROM A
INNER JOIN
(
SELECT col1 AS test FROM B
UNION
SELECT col2 AS test FROM B
) C
ON A.test = C.test
Related
I'm just getting started learning SQL Server Management Studio. I'm familiar with building nested queries in Access, e.g.:
Query1 (get a data set)
select t1.a,t2.b,t1.abc,t2.def from tbl_FNA t1
inner join
tbl_DMZ t2 on
t1.b=t2.b
Query2 (return only the rows from Query1 with the minimum value of b)
select q1.* from Query1 q1
inner join
(select a,min(b) as min_b from Query1 group by a) q2
on
q1.a=q2.a
and
q1.b=q2.min_b
This makes it easier to debug the code because if there's something wrong with Query1, I only have to change it in one place instead of 3 places.
I'm aware that if I have write access to the database, I can create views and/or stored procedures that can help with this. But in this case, I have read-only access.
Is there a way in SSMS that I can save a query and then refer to that query by name inside another query?
You can do this inside the 'session' using a CTE, but without write access you can't save any objects to the database.
WITH q2 AS
(select a,min(b) as min_b from Query1 group by a)
select q1.* from
Query1 q1
inner join
q2
on
q1.a=q2.a
and
q1.b=q2.min_b
SELECT * FROM q2
SELECT TOP 1000 * FROM q2
I am having a problem. My Lookup table is producing MORE records than my original query..
I feel I am missing something basic. How do I prevent ending up with more records by bringing in a column or two from the 2nd table?
-- 140930
SELECT COUNT(ID)
FROM dbo.USER_ACCOUNTS AS A
-- 143324
LEFT JOIN dbo.DOMAIN AS B
ON A.Domain = B.DOMAIN
As you can see my count grows to 143324 after the join. I have tried outer joins as well. There are only 150 or so domains to join on. AND some should not even be in the results because no domain match should be found!?
This is SQL SERVER 2008 R2
|Thanks|
SELECT COUNT(ID)
FROM dbo.USER_ACCOUNTS AS A
WHERE EXISTS (
SELECT 1
FROM dbo.DOMAIN AS B
WHERE A.Domain = B.DOMAIN
)
I have a sql server query that returns rows more than I expected:
select
b.isbn, l.lend_no, s.first_name
from
dbo.books b, dbo.lending l, dbo.students s
where
(l.act between '4/16/2013' and '4/16/2013')
and (l.stat ='close')`
I want to do is get the isbn, lend_no and student name that book returned date is between given dates and lend status is closed , my lending table has only 2 lending that returned on given date but query give me 304 rows
Your current query gets the cartesian product from the three tables causing to retrieve unexpected result. You need to define the relationship or how the tables should be join, example
select b.isbn, l.lend_no, s.first_name
from dbo.books b
INNER JOIN dbo.lending l
ON c.Colname = l.ColName -- << define condition here
INNER JOIN dbo.students s
ON ...... -- << define condition here
where l.act between '4/16/2013' and '4/16/2013' and
l.stat ='close'
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
You're not definining any join conditions between the tables, so you'll get a cartesian product.
Try something like this instead:
SELECT
b.isbn, l.lend_no, s.first_name
FROM
dbo.books b
INNER JOIN
dbo.lending l ON l.Book_id = b.Book_id -- just guessing here
INNER JOIN
dbo.students s ON l.student_id = s.student_id -- just guessing here
WHERE
l.act BETWEEN '20130416' AND '20130416'
AND l.stat = 'close'
Define the join conditions as needed - I don't know your tables, you'll have to find out what columns link the two tables respectively.
I also used the proper ANSI JOIN syntax - don't just list a bunch of tables separated by a comma, that's been kicked out of the SQL standards over 20 years ago (SQL 1992).
Also: I would always use the ISO-8601 date format YYYYMMDD to be safe - this is the only format that works on all versions of SQL Server and with all language, regional and dateformat settings.
Your FROM clause isn't doing what you expect it to. By specifying the tables that way you are doing a full join which is giving you a cartesian product. You need to be using the proper table join syntax.
This is a great explanation of table joins: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
I have been fighting with this all weekend and am out of ideas. In order to have pages in my search results on my website, I need to return a subset of rows from a SQL Server 2005 Express database (i.e. start at row 20 and give me the next 20 records). In MySQL you would use the "LIMIT" keyword to choose which row to start at and how many rows to return.
In SQL Server I found ROW_NUMBER()/OVER, but when I try to use it it says "Over not supported". I am thinking this is because I am using SQL Server 2005 Express (free version). Can anyone verify if this is true or if there is some other reason an OVER clause would not be supported?
Then I found the old school version similar to:
SELECT TOP X * FROM TABLE WHERE ID NOT IN (SELECT TOP Y ID FROM TABLE ORDER BY ID) ORDER BY ID where X=number per page and Y=which record to start on.
However, my queries are a lot more complex with many outer joins and sometimes ordering by something other than what is in the main table. For example, if someone chooses to order by how many videos a user has posted, the query might need to look like this:
SELECT TOP 50 iUserID, iVideoCount FROM MyTable LEFT OUTER JOIN (SELECT count(iVideoID) AS iVideoCount, iUserID FROM VideoTable GROUP BY iUserID) as TempVidTable ON MyTable.iUserID = TempVidTable.iUserID WHERE iUserID NOT IN (SELECT TOP 100 iUserID, iVideoCount FROM MyTable LEFT OUTER JOIN (SELECT count(iVideoID) AS iVideoCount, iUserID FROM VideoTable GROUP BY iUserID) as TempVidTable ON MyTable.iUserID = TempVidTable.iUserID ORDER BY iVideoCount) ORDER BY iVideoCount
The issue is in the subquery SELECT line: TOP 100 iUserID, iVideoCount
To use the "NOT IN" clause it seems I can only have 1 column in the subquery ("SELECT TOP 100 iUserID FROM ..."). But when I don't include iVideoCount in that subquery SELECT statement then the ORDER BY iVideoCount in the subquery doesn't order correctly so my subquery is ordered differently than my parent query, making this whole thing useless. There are about 5 more tables linked in with outer joins that can play a part in the ordering.
I am at a loss! The two above methods are the only two ways I can find to get SQL Server to return a subset of rows. I am about ready to return the whole result and loop through each record in PHP but only display the ones I want. That is such an inefficient way to things it is really my last resort.
Any ideas on how I can make SQL Server mimic MySQL's LIMIT clause in the above scenario?
Unfortunately, although SQL Server 2005 Row_Number() can be used for paging and with SQL Server 2012 data paging support is enhanced with Order By Offset and Fetch Next, in case you can not use any of these solutions you require to first
create a temp table with identity column.
then insert data into temp table with ORDER BY clause
Use the temp table Identity column value just like the ROW_NUMBER() value
I hope it helps,
I have a SQL Server 2005 database that is linked to an Oracle database. What I want to do is run a query to pull some ID numbers out of it, then find out which ones are in Oracle.
So I want to take the results of this query:
SELECT pidm
FROM sql_server_table
And do something like this to query the Oracle database (assuming that the results of the previous query are stored in #pidms):
OPENQUERY(oracledb,
'
SELECT pidm
FROM table
WHERE pidm IN (' +
#pidms + ')')
GO
But I'm having trouble thinking of a good way to do this. I suppose that I could do an inner join of queries similar to these two. Unfortunately, there are a lot of records to pull within a limited timeframe so I don't think that will be a very performant option to choose.
Any suggestions? I'd ideally like to do this with as little Dynamic SQL as possible.
Ahhhh, pidms. Brings back bad memories! :)
You could do the join, but you would do it like this:
select sql.pidm,sql.field2 from sqltable as sql
inner join
(select pidm,field2 from oracledb..schema.table) as orcl
on
sql.pidm = orcl.pidm
I'm not sure if you could write a PL/SQL procedure that would take a table variable from sql...but maybe.....no, I doubt it.
Store openquery results in a temp table, then do an inner join between the SQL table and the temp table.
I don't think you can do a join since OPENQUERY requires a pure string (as you wrote above).
BG: Actually JOIN IN SQLServer to Oracle by OpenQuery works, avoiding #tmp table and allowing JOIN to SQL without Param* - ex.
[SQL SP] LEFT JOIN OPENQUERY(ORADB,
'SELECT COUNT(distinct O.ORD_NUM) LCNT,
O.ORD_MAIN_NUM
FROM CUSTOMER.CUST_FILE C
JOIN CUSTOMER.ORDER_NEW O
ON C.ID = O.ORD_ID
WHERE C.CUS_ID NOT IN (''2'',''3'')
GROUP BY O.ORD_MAIN_MACNUM') LC
ON T.ID = LC.ORD_MAIN_ID*
Cheers, Bill Gibbs