T-SQL Skip cte Table and Union when Variable Is Null - sql

I've got a query that captures all shipments and costs from our factory. Sample data and desired output on Google Drive here:
https://drive.google.com/open?id=0B4xdnV0LFZI1VndEaGgxNDVpU2M
The issue is we've got 2 different ways of selling things. One is 'Regluar' where we make it and the other one is a 'buy/sell' where we buy and sell it.
To capture the costs I've had to write two queries, one for each scenario. The end users of this query can enter in a date range and the query works well then, but I'm stuck when it comes to the variable #Job_No.
All work that goes through our factory (cteRegularJobs) has a Job Number associated with it and I've declared a variable so users can use it to search. The cteBuyandSell has a value of 'NULL' for Job_No declared in the SELECT statement so I can do a UNION of these two tables at the end. However, no buy/sell jobs have Job Numbers assigned to them, they are always NULL.
Initially #Job_No is declared as '' and when it's left '' I want the results from both cte tables returned. If there is an entry by the user, i.e. '001' then I want results for cteRegularJobs.
If it makes it easier I am open to declaring the cteBuyandSell.Job_No something else besides NULL, like "Buy and Sell".
The real query is complicated so here's a simplified example of the structure:
DELCARE #Job_No AS varchar(10) = '';
SET #Job_No = {User Input or leave as ''};
WITH
cteBuyandSell AS ( NULL AS 'Job_No',
...),
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT *
FROM
(cteBuyandSell
UNION
cteRegularJobs)

You can logically break this up with an IF statement to check the value of your variable. I'd suggest NULL over white space though. Here's an example procedure... with the limited code you provided.
CREATE PROCEDURE getData(#Job_No varchar(10) = NULL)
AS
IF #Job_No IS NULL
BEGIN
WITH
cteBuyandSell AS ( NULL AS 'Job_No',
...),
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT *
FROM
(cteBuyandSell
UNION
cteRegularJobs)
END
ELSE
BEGIN
WITH
cteRegularJobs AS (tblJobs.Job_No AS 'Job_No',
...
WHERE tblJobs.Job_No LIKE #Job_No)
SELECT * FROM cteRetularJobs
END

Related

SQL Query to get all the data from tables when there is no parameter

I am trying to get the whole data when there are no filters selected. I have made an array that contains the selections. In case there are no selections then there will be just '' , i.e. no characters but not null.
SELECT * FROM Skills WHERE person IN ('Technology', 'Drilling');
For example - In this query it will return all required - filtered data. So my array contains Technology and Drilling. In case there is nothing selected by the user as a filter then the query would look like:
SELECT * FROM Skills WHERE person IN ('');
In this case the table is returning nothing in SQL Server. I want it to return everything from the table without any filters.
I would really like to get some help here and maybe some resources that might help me achieve the required thing.
The array is being filled in javascript.
It seems really strange to have a column called person compared to values like "Drilling". But you would do something like:
SELECT *
FROM Skills
WHERE person IN (<whatever>) OR <whatever> = '';
Often NULL is used to mean everything, so that would be:
WHERE person IN (<whatever>) OR <whatever> IS NULL;
And "whatever" might be a delimited string, so this might look like:
WHERE person IN (SELECT s.value FROM string_split(#params) s) OR
#params IS NULL;

Finding Where Clause Criteria in SQL Queries

I have a Table which has 3 different Select queries.
e.g.
Staff
------------------------------------------------------------
ID Code Name Phone DOB Email Addr1 Addr2 Addr3
Query1
Select ID, Code, Phone From Staff Where Code = 'ABC'
Query2
Select ID, Code, Phone From Staff Where Name = 'ABCXYZ' And Code = 'B'
Query3
Select ID, Code, Phone From Staff Where Phone= '1234' And Email = 'a#b'
These 3 queries are there in 3 different stored procedure.
I want to find the names of Attributes which i have used in all my Where clauses. But want to Automate this as I have more than 100 tables to look for
Something like this
exec fxGetWhereColList ('Staff');
Result:
Code
Name
Phone
Email
I agree with all posts before, it's a complex case.
I post you a small idea to help you in your work.
If you can retrieve each execution plan, you can parse XML result and get the impacted columns.
For example: On the node <Predicate>
Like Lamak says, doing this right is nearly impossible, at least in SQL.
To do it properly you should use a SQL Parser for the SQL variant you are using. A SQL Parser will identify the objects referenced in the statement, and the elements of the where clauses.
But if you know that the queries are simple and look like the one you are listing, you can use some simple queries to pick apart the statements. I have made an example for a single statement:
declare
#foo nvarchar(max)=N'Select ID, Code, Phone From Staff Where Phone= ''1234'' And Email = ''a#b'' '
, #From nvarchar(max)=' From '
, #Table nvarchar(max)
declare #a int
-- find FROM
set #a= PATINDEX('%'+#From+'%',#foo)
-- Find statement to the right of from
set #foo=ltrim(RIGHT(#foo,len(#foo)-(#a)))
-- Find first space
set #a=CHARINDEX(' ',#foo)
-- find first word, we assume it is the table name
set #Table=ltrim(rtrim(LEFT(#foo,#a)))
-- Find WHERE statement
set #foo=ltrim(rtrim(replace(right(#foo,len(#foo)-#a),'Where','')))
-- Now find matching columns in table, I am using SQL Server so I look up column names in information_schema.columns
select #Table,column_name
from INFORMATION_SCHEMA.COLUMNS
--from (values ('ID'),('Code'),('Name'),('Phone'),('DOB'),('Email'),('Addr1'),('Addr2'),('Addr3'))cols(column_name)
where TABLE_NAME=#table
and #foo like '%'+column_name+'%'
This solution will only work for some simple statements, it assumes a lot of stuff.

SQL - String Logic

I don't know if what I am wanting to achieve is possible so here is my conundrum.
Within a SQL table there are a number of fields that contain yes/no flags in a string so for example. On the field may be be called 'Stock' and within this one field there is a string of flags which e.g. 'YNYYY' lets say for example that the flags stand for.
Coke
Fanta
Pepsi
Lilt
Dr Pepper
in this instance I would want in my return of data to return Coke,Pepsi,Lilt,Dr Pepper ommiting the Fanta.
Now this would be possible using the CASE Statement and this may be the answer that I have to use, however ideally so I don't have to write hundreds of different variables anyone know of a way this could be achieved?
Your help as always appreciated, I've done the normal googling and maybe I simply don't know what to search for as its giving me blanks.
Please point me in the right direction.
Regards
R
Why dont you use SELECT with WHERE?
Something like this.
SELECT GROUP_CONCAT(`Stock`)
FROM table_name
WHERE `flag` = 'Y'
Hope this helps.
One way you can achieve your goal is by writing a table valued function that turns your Y/N string into a table of (Id INT, value BIT), you could then join to a look up table based on convention. Here's what something like this would look like:
CREATE FUNCTION udf_StringToBool(#intput varchar(100))
RETURNS #table TABLE (
Id INT IDENTITY(1,1),
Value BIT
)
AS
begin
declare #temp_input varchar(100) = #intput
while len(#temp_input) > 0
begin
insert into #table (value)
SELECT CASE LEFT(#temp_input, 1) WHEN 'Y' THEN 1 ELSE 0 END
set #temp_input = right(#temp_input, len(#temp_input)-1)
END
RETURN
end
You would then join your stock (and a lookup to product) table with this function, then remove any that are not in stock in the WHERE clause:
SELECT s.*, v.Value, pl.Name
FROM
stock s
cross apply
(
select b.* from udf_StringToBool(s.Flags) b
) v
join product_lookup pl on pl.Id = v.Id
WHERE v.Value = 1
Here's how you would define the lookup table:
create table product_lookup
(
Id INT IDENTITY(1,1),
Name Varchar(50)
)
insert into product_lookup (Name) values
('Coke'),
('Fanta'),
('Pepsi'),
('Lilt'),
('Dr Pepper')
Then you could use PIVOT to generate the columns with booleans.
In the end I chose to use 'substring' and the 'case' statement so that each item appeared in it's own field this way I mitigated the need to write every variable.
SELECT CASE WHEN SUBSTRING(STOCK,1,1) = 'y' THEN 'IN STOCK' ELSE 'OUTOFSTOCK' END AS COKE
I don't know why it didnt occur to me to begin with and without your prompting and guidance I would have probably done this the long way round as ever thanks to all!

How to use case statement to declare a local variable for a subsequent subquery?

Is it possible to declare a local variable depending on the case and then fire a common subquery?
Pseudo code:
SELECT
CASE
WHEN TABLE.TYPE = 'STUDENT' variable = "UNIVERSITY"
WHEN TABLE.TYPE = 'EMPLOYEE' variable = "EMPLOYER"
(Some big query here it has a common joins / groupings but the variable changes)
END AS NAME
FROM TABLE
Looking for a SQL Server solution.
Scenario is like this - I have a query that lists some member information . Now I need to get some addendum data to an existing query - I mean result set won't change . I can actually join but then I have to filter out many things - Does that make sense ? Imagine I was display all the members in the table and someone asks me to show the univeristy name or the employer name . And the biggest problem is a member can have more than one university he attended - same for employer . Isn't joins really bad on performance in this case ? Since there are many one to many stuff . Also please note I finally display only 10 records as part of pagination so I thought I should do a case statement .
DECLARE #variable varchar(10)
SELECT #variable =
CASE
WHEN t.TYPE = 'STUDENT' THEN 'UNIVERSITY'
WHEN t.TYPE = 'EMPLOYEE' THEN 'EMPLOYER'
ELSE 'Undefined'
END
FROM TableName t
MSDN - SELECT #local_variable
If the SELECT statement returns more than one value, the variable is
assigned the last value returned.

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.