NOT IN Operation on multilple value (Sybase SQL) - sybase

I am trying to write a SQL like:
SELECT *
FROM TABLE1
WHERE (TABLE1.A, TABLE1.B) NOT IN
(SELECT TABLE2.A, TABLE2.B FROM TABLE2)
It seems this is not allowed in Sybase.
Can someone tell me how to fix this?

IN and NOT IN indeed work only on a single column.
The solution is not so difficult: concatenate the columns into a single value. For example, if both are VARCHAR columns, do something like this:
WHERE (TABLE1.A||'~~~'||TABLE1.B) NOT IN
(SELECT TABLE2.A||'~~~'||TABLE2.B FROM TABLE2)
This assumes that the string '~~~' will not occur in the data -- pick any string that works for you.

Related

How do I use the contents of a SQL column as a database name in another select's from statement?

I have a database that contains a table. wherein one of the columns in that table is [database_name]. I want to use the contents of that column to link to a table in another database and return the contents of one of the columns in that table.
Here's what I'm trying to do, but it doesn't work.
SELECT t1.col1
,t1.col2
,t1.col3
,t1.database_name
,t1.cust_id
,(SELECT t2.ordered_on
FROM [t1.database_name].[dbo].[order_info] t2
WHERE t2.cust_id = t1.cust_id
) as order_placed_on
FROM [my_database].[dbo].[table1] t1
ORDER BY order_placed_on DESC
The problem, of course, is that SQL Server takes the [t1.data_source] thing literally, and doesn't substitute the CONTENTS of the column t1.data_source.
I also tried declaring a variable #databaseName and using #databaseName.[dbo].[order_info] but I can't seem to get that to work either. Here's the example of that non-working code:
DECLARE #databaseName nvarchar(50)
SELECT t1.col1
,t1.col2
,t1.col3
,t1.database_name
,#databaseName = t1.database_name
,t1.cust_id
,(SELECT t2.ordered_on
FROM #databaseName.[dbo].[order_info] t2
WHERE t2.cust_id = t1.cust_id
) as order_placed_on
FROM [my_database].[dbo].[table1] t1
ORDER BY order_placed_on DESC
That code gives me
Incorrect syntax near '.'"
Clearly it doesn't like the #databaseName.[dbo].[order_info] format. And if I add brackets around the #dataSource variable, so it looks like [#databaseName].[dbo].[order_info] I get a "A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations." error. No clue why. select #variableName = column_name is precisely how you assign data to a variable in a select statement. So I have no idea what's going on there... Something is getting it confused, but I don't know what, and at this point, I just need this stupid thing to work.
Anyway, I just need to know how to make SQL Server substitute the CONTENTS of the column for the column name (or variable name) in that second select's from statement.

SQL Server - Find out if string returned in subquery contains another string

I have two tables. One has a separate rows for each ID. The other has a string with a comma separated list of IDs. I'm trying to find out if the ID from the first table appears anywhere within the string of comma separated IDs in the second table.
Here's a sample (non-working) query:
select * from
(select 'b' as ID) table1
where table1.ID in
(select 'a,b,c' as CSV_LIST)
This is not how IN works, of course, but I don't know how else to approach this.
I've thought about using STRING_SPLIT() but it doesn't work in this version of SQL Server. I've also thought about using CONTAINS() but I can't seem to get it to work either.
Any ideas?
You can use LIKE or a custom string splitter like Jeff Moden's if you can't fix the design.
select table1.*
from table1
inner join table2
on table2.csv like '%' + table1.b + '%'
Note, this isn't SARGable because of the leading % so as Sean pointed out, fixing the design would be best, followed by another split function that doesn't use a WHILE loop.

Is this a SQL Parser bug? Or my misunderstanding?

Using SQL Server 2008 R2 (Version 10.50.4000.0):
I have two tables. I want to delete data in one table where an ID exists in another table. Simple enough. However, due to a mistake in typing, I found what appears to be a parser bug.
In the script below, [SomeID] is a column in Table1 but does not actually exist in Table2
Delete from Table1 where [SomeID] in (Select [SomeID] from Table2)
If you run the subquery "Select [SomeID] from Table2, you get an appropriate error message stating that the column does not exist.
If you run the whole delete query though, it runs without error, and deletes everything in table1
It seems that the parser should have caught that the column did not exist in table 2. I know you can use columns from outside the sub-query, and I realize that the parser was assuming that I meant to use a column from table1, but since I had not specified any columns from table2, the parser should have, in my opinion, been smart enough to know there was something wrong. Fortunately, we were in a test environment when this happened. :)
Thanks,
Tony
It's not an error
The engine will do what you put in the query.
when you use In clause, it will compare for each row, the field SomeId, with the result in the In
For example, you could do this
Delete from Table1 where [SomeID] in (Select [SomeID] from Table2 where IdTable2 = SomeId)
So, you could return anything in the select, as a constant, as an Id in the table2, a sum of both, or, like this case, the ID in the first Table.
In this case, when execute the subquery, as doesn't have a where clause, the subquery will always return a result (unless got no rows), because it doesn't have a filter, but what will show ? You're specifying a field in the parent-query, and you're able to show it, so it will return it.
Of corse, as you're comparing with In, so is deleting all in table1, right ?

Possible to test for null records in SQL only?

I am trying to help a co-worker with a peculiar problem, and she's limited to MS SQL QUERY code only. The object is to insert a dummy record (into a surrounding union) IF no records are returned from a query.
I am having a hard time going back and forth from PL/SQL to MS SQL, and I am appealing for help (I'm not particularly appealing, but I am appealing to the StackOverflow audiance).
Basically, we need a single, testable value from the target Select ... statement.
In theory, it would do this:
(other records from unions)
Union
Select "These" as fld1, "are" as fld2, "Dummy" as fld3, "Fields" as fld4
where NOT (Matching Logic)
Union
Select fld1, fld2, fld3, fld4 // Regular records exist
From tested_table
Where (Matching Logic)
Forcing an individual dummy record, with no conditions, works.
IS there a way to get a single, testable result from a Select?
Can't do it in code (not allowed), but can feed SQL
Anybody? Anybody? Bbeller?
You could put the unions in a with, then include another union that returns a null only when the big union is empty:
; with BigUnion as
(
select *
from table1
union all
select *
from table2
)
select *
from BigUnion
union all
select null
where not exists (select * from BigUnion)

Count of Distinct Rows Without Using Subquery

Say I have Table1 which has duplicate rows (forget the fact that it has no primary key...) Is it possible to rewrite the following without using a JOIN, subquery or CTE and also without having to spell out the columns in something like a GROUP BY?
SELECT COUNT(*)
FROM (
SELECT DISTINCT * FROM Table1
) T1
You can do something like this.
SELECT Count(DISTINCT ProductName) FROM Products
but if you want a count of completely distinct records then you will have to use one of the other options you mentioned.
If you wanted to do something like you suggested in the question, then that would imply you have duplicate records in your table.
If you didn't have duplicate records SELECT DISTINCT * from table would be the same without the distinct.
No, it's not possible.
If you are limited by your framework/query tool/whatever, can't use a subquery, and can't spell out each column name in the GROUP BY, you are SOL.
If you are not limited by your framework/query tool/whatever, there's no reason not to use a subquery.
if you really really want to do that you can just "SELECT COUNT(*) FROM table1 GROUP BY all,columns,here" and take the size of the result set as your count.
But it would be dailywtf worthy code ;)
I just wanted to refine the answer by saying that you need to check that the datatype of the columns is comparable - otherwise you will get an error trying to make them DISTINCT:
e.g.
com.microsoft.sqlserver.jdbc.SQLServerException: The ntext data type cannot be selected as DISTINCT because it is not comparable.
This is true for large binary, xml columns and others depending on your RDBMS - rtm. The solution for SQLServer for example is to cast it from an ntext to an nvarchar(MAX) from SQLServer 2005 onwards.
If you stick to the PK columns then you should be OK (I haven't verified this myself but I'd have thought logically that PK columns would have to be comparable)

Resources