How to select items with all possible id-s or just a particular one using the same query? - sql

Is there a variable in SQL that can be used to represent ALL the possible values of a field? Something like this pseudo-code
SELECT name FROM table WHERE id = *ALL_EXISTING_ID-s*
I want to return all rows in this case, but later when I do a search and need only one item I can simply replace that variable with the id I'm looking for, i.e.
SELECT name FROM table WHERE id = 1

The simplest way is to remove the WHERE clause. This will return all rows.
SELECT name FROM table
If you want some "magic" value you can use for the ID that you can use in your existing query and it will return all rows, I think you're out of luck.
Though you could use something like this:
SELECT name FROM table WHERE id = IFNULL(?, id)
If the value NULL is provided, all rows will be returned.
If you don't like NULL then try the following query, which will return all rows if the value -1 is provided:
SELECT name FROM table WHERE id = IFNULL(NULLIF(?, -1), id)
Another approach that achieves the same effect (but requires binding the id twice) is:
SELECT name FROM table WHERE (id = ? OR ? = -1)

Related

SQL Parameter to Include All on ID Column

I'm just taking a look at the following query
select * from tablename
where id like '%%';
So that it can handle parameters to include all of the data or filtered data like bellow
select * from tablename
where id like '%1%';
Which is fine for most parameters I use but this seems wrong for an ID because it will return all data that has IDs containing 1 which I don't want
To get around this I can only append the where clause if the ID is given but that seems like a pain in the butt
Is it possible to use a different type of where clause so that a wildcard can be used in a where equals clause instead of a where like clause, example
select * from tablename
where id = '*';
So that the same query can be used to return all or filtered data? Pass parameter '*' for all or parameter '1' for ID 1 specifically
(I'm not sure if it matters for this case but I'm using PostgreSQL 9.6.12 in this example)
This would often be expressed as:
where (id = :id or :id is null)
null is the "magic" value that represents all rows.

Oracle Coalesce returns blank

I have following query which uses coalesce to return the id of a calendar with a specific code
SELECT COALESCE(SD_CALENDAR.ID,0) FROM SD_CALENDAR WHERE SD_CALENDAR.CODE = 'BOER';
But when I run this I get a blank column as result, instead of 0. What do I need to change to make my query work?
You said that no rows in your table match your query, so you are trying to return 0 when there is no match, rather than returning no data at all.
If NAME is unique then you could use an aggregate to achieve this:
SELECT COALESCE(MAX(SD_CALENDAR.ID),0) FROM SD_CALENDAR WHERE SD_CALENDAR.CODE = 'BOER';
The MAX() will always return one row; if there is a match it will be the single ID anyway, and if there isn't it will be null - which you can then coalesce to zero.
If NAME isn't unique and you expect multiple values back then you can use a union to provide the zero value when there is no match:
SELECT COALESCE(SD_CALENDAR.ID,0) FROM SD_CALENDAR WHERE SD_CALENDAR.CODE = 'BOER'
UNION ALL
SELECT 0 FROM DUAL WHERE NOT EXISTS (
SELECT COALESCE(SD_CALENDAR.ID,0) FROM SD_CALENDAR WHERE SD_CALENDAR.CODE = 'BOER'
);
Depending on what you're doing, it might be better/easier to let your application handle a no-data-found result and substitute a zero itself.

SQL - Retrieve records based on parameters where either parameter can be null

I have a stored procedure which takes in five parameters of which two can be null - we will call these parameters A and B
What I would like to do is select records based on the following logic.
If Parameter A is NULL then only return records that match Parameter B
I know that I can do something similar to the following
IF A IS NULL
BEGIN
SELECT * FROM TABLE WHERE Param=B
END
ELSE
BEGIN
SELECT * FROM TABLE WHERE Param=A
END
However, the SQL query is much more complex then the above one and there would be huge replication in the Proc which is something I want to avoid
Thanks in advance
===============================
EDIT - Sorry, I should have mentioned that in the example the Param are based on separate columns e.g.
My table consists of four columns of which two separate columns map to the two parameters - basic schema below
ID
PersonName
GroupID
DeliveryID
In my procedure I want to retrieve those records that match the GroupID however in the scenario where the GroupID is null then I want to return those records that match the DeliveryID
Thanks again
Try
SELECT * FROM my_table WHERE Param = COALESCE(A,B)
COALESCE will give you A if it's not null. Otherwise B.
Functionally, something like this should work. If either parameter is NULL, the condition becomes a self-identity (assuming neither groupID nor deliveryID is NULL).
SELECT *
FROM table_name
WHERE groupID = coalesce(#groupIDParameter, groupID)
AND deliveryID = coalesce(#deliveryIDParameter, deliveryID)
Try ISNULL function:
SELECT * FROM TABLE WHERE Param = ISNULL(B,A)
You could also use a case statement Case when A is Null Then B

How can I iterate through SQL results like a for loop and an array?

I have a table, and I want to select only the single column of row IDs from it, but in a specific order. Then, I want to loop through that column like below:
for (i=0; i<rows.length; i++)
{
if(i==rows.length-1)
UPDATE myTable SET nextID = NULL WHERE ID = rows[i]
ELSE
UPDATE myTable SET nextID = rows[i+1] WHERE ID = rows[i]
}
I just dont know how to access the results of my select statement with an index like that. Is there a way of doing this in sql server?
Since you didn't provide many details, let's pretend your table looks something like this:
create table MyTable (
Id int not null primary key,
Name varchar(50) not null,
NextId int
)
I want to select only the single column of row IDs from it, but in a specific order
Let's just say that in this case, you decide to order the rows alphabetically by Name. So let's pretend that the select statement that you want to loop through looks like this:
select Id
from MyTable
order by Name
That being the case, instead of looping through the rows and attempting to update each row using the pseudo-code you provided, you can replace the whole thing with a single update statement that will perform the exact same work:
with cte as (
select *,
NewNextId = lead(Id) over (order by Name)
from MyTable
)
update cte
set NextId = NewNextId
Just make sure to adjust the order by clause to whatever your specific order really is. I just used Name in my example, but it might be something else in your case.
You could use a cursor, or you could use something a bit smarter.
Your example should be able to be written fairly easily along the lines of:
update mytable set nextID = LEAD(id,1) over (order by id)
Lead(id,1) will grab the next id, 1 row ahead in the record set and update the nextID field with it. If it can't find one it will return null. No looping or conditional logic needed!
edit: I forgot the over clause. This is the part that tells it how you would like it ordered for the lead

How do you query an int column for any value?

How can you query a column for any value in that column? (ie. How do I build a dynamic where clause that can either filter the value, or not.)
I want to be able to query for either a specific value, or not. For instance, I might want the value to be 1, but I might want it to be any number.
Is there a way to use a wild card (like "*"), to match any value, so that it can be dynamically inserted where I want no filter?
For instance:
select int_col from table where int_col = 1 // Query for a specific value
select int_col from table where int_col = * // Query for any value
The reason why I do not want to use 2 separate SQL statements is because I am using this as a SQL Data Source, which can only have 1 select statement.
Sometimes I would query for actual value (like 1, 2...) so I can't not have a condition either.
I take it you want some dynamic behavior on your WHERE clause, without having to dynamically build your WHERE clause.
With a single parameter, you can use ISNULL (or COALESCE) like this:
SELECT * FROM Table WHERE ID = ISNULL(#id, ID)
which allows a NULL parameter to match all. Some prefer the longer but more explicit:
SELECT * FROM Table WHERE (#id IS NULL) OR (ID = #id)
A simple answer would be use: IS NOT NULL. But if you are asking for say 123* for numbers like 123456 or 1234 or 1237 then the you could convert it to a varchar and then test against using standard wild cards.
In your where clause: cast(myIntColumn as varchar(15)) like '123%'.
Assuming the value you're filtering on is a parameter in a stored procedure, or contained in a variable called #Value, you can do it like this:
select * from table where #Value is null or intCol = #Value
If #Value is null then the or part of the clause is ignored, so the query won't filter on intCol.
The equivalent of wildcards for numbers are the comparators.
So, if you wanted to find all positive integers:
select int_col from table where int_col > 0
any numbers between a hundred and a thousand:
select int_col from table where int_col BETWEEN 100 AND 1000
and so on.
I don't quite understand what you're asking. I think you should use two different queries for the different situations you have.
When you're not looking for a specific value:
SELECT * FROM table
When you are looking for a specific value:
SELECT * FROM table WHERE intcol = 1
You can use the parameter as a wildcard by assigning special meaning to NULL:
DECLARE #q INT = 1
SELECT * FROM table WHERE IntegerColumn = #q OR #q IS NULL
This way, when you pass in NULL; you get all rows.
If NULL is a valid value to query for, then you need to use two parameters.
If you really want the value of your column for all rows on the table you can simply use
select int_col
from table
If you want to know all the distinct values, but don't care how many times they're repeated you can use
select distinct int_col
from table
And if you want to know all the distinct values and how many times they each appear, use
select int_col, count(*)
from table
group by int_col
To have the values sorted properly you can add
order by int_col
to all the queries above.
Share and enjoy.