Is putting a OR condition when Selecting/Displaying columns valid? - sql

new to SQL, I was wondering if its valid to put a "or" condition when choosing columns (SELECT)?
Example:
SELECT (Column1 OR Column2)
My Aim:
I'm currently creating a view that will display all claim types basic information that I will use for queries. Obviously, they are in different tables, so I was hoping to merge them into one view for easy access. The problem is when created the view puts the columns with OR statement to either a 1 or 0, when it should be a VARCHAR (string).
Full SQL Query:
CREATE VIEW ViewAllClaims AS
SELECT Claim.ClaimID, Claim.CreatedDate, (ReturnClaim.ClaimStatus or RepairClaim.ClaimStatus) as 'ClaimStatus', (SupplierName or FirstName) as 'Name'
FROM Claim, ReturnClaim, RepairClaim, Supplier, Product, ReturnClaimProduct, Customer
WHERE ( Claim.ClaimID = ReturnClaim.ClaimID
AND ReturnClaim.ClaimID = ReturnClaimProduct.ClaimID
AND ReturnClaimProduct.Keycode = Product.Keycode
AND Product.SupplierID = Supplier.SupplierID)
or
(Claim.ClaimID = RepairClaim.ClaimID
AND RepairClaim.CustomerID = Customer.CustomerID);
Screenshot of the result:

You can use CASE:
SELECT (
CASE
WHEN ReturnClaim.ClaimStatus IS NULL THEN RepairClaim.ClaimStatus
ELSE ReturnClaim.ClaimStatus
END
) AS 'ClaimStatus'
FROM ...

Related

Selecting all data if the string is empty in SQL IN operator

I have a stored procedure for the Filters of products in my website which goes like:
ALTER PROCEDURE [dbo].[sp_product_get_by_filters]
(#brand_names nvarchar(max),
#type nvarchar(max))
AS
BEGIN
SELECT
tbl_product.product_code,
tbl_product.brand_name,
tbl_product.subcategory_code,
tbl_product.product_name,
tbl_product.product_photo_1,
tbl_product.filter_code,
(select filter_name from tbl_filter where filter_code = tbl_product.filter_code )as filter_name,
(select AVG(CAST(rating AS DECIMAL(10,2))) from tbl_review where product_code = tbl_product.product_code) as Rating,
(select TOP 1 sub_product_price from tbl_sub_product where product_code = tbl_product.product_code) as product_price,
(select TOP 1 size from tbl_sub_product where product_code = tbl_product.product_code) as size,
(select TOP 1 sub_product_code from tbl_sub_product where product_code = tbl_product.product_code) as sub_product_code
FROM
tbl_product
WHERE
tbl_product.brand_name IN (SELECT * FROM dbo.splitstring(#brand_names))
AND tbl_product.filter_code IN (SELECT * FROM dbo.splitstring(#type))
END
#brand_names here is a string of the name of brands separated by comma for example
Apple,Samsung,Nokia
and #type is the filter of the products which is like
'Watch,Mobile,Tablet'
The dbo.splitstring function separates each value from the concatenated string and return the list as a table. So the problem when a User select both Brand Name and Type the query returns the values but if a user select only Brand Name or Type the query doesn't return anything. I want to make the query to return the products if the user select both Brand Name and Type or don't select any of them (You know like filters in every e-commerce website). If the user doesn't select any filter I am passing an empty string in variables like if user doesn't select any brand then #brand_names will be #brand_names = ''.
For example if a user select Brand Name Apple the query must return all the products related to this brand. And again if the user select the Type watch then the query must return the Watches from brand Apple. I am using SQL Server 2008.
Thank you for the Help.
For this kind of "optional parameter" query, an option recompile at the end can improve performance by quite a lot.
If an "unselected" parameter is an empty string, then you can do:
WHERE
(#brand_names = '' or tbl_product.brand_name IN (SELECT * from dbo.splitstring(#brand_names)))
and (#type = '' or tbl_product.filter_code IN (SELECT * from dbo.splitstring(#type)))
option (recompile)
The option (recompile) tells SQL to build a new plan for this statement every time the procedure runs. So, for example, if you pass an empty string for #brand_names, the engine doesn't even need to evaluate the or tbl_product.brand_name in ... part of that predicate. If you don't do this, then SQL will - as always - build a plan for the first execution, and then reuse that plan on subsequent executions. That's not great when different parameter values can make such a big difference to the result.

I need to create a VIEW from an existing TABLE and MAP an additional COLUMN to that VIEW

I am fairly new to SQL. What I am trying to do is create a view from an existing table. I also need to add a new column to the view which maps to the values of an existing column in the table.
So within the view, if the value in a field for Col_1 = A, then the value in the corresponding row for New_Col = C etc
Does this even make sense? Would I use the CASE clause? Is mapping in this way even possible?
Thanks
The best way to do this is to create a mapping or lookup table
For example consider the following LOOKUP table.
COL_A NEW_VALUE
---- -----
A C
B D
Then you can have a query like this:
SELECT A.*, LOOK.NEW_VALUE
FROM TABLEA AS A
JOIN LOOKUP AS LOOK ON A.COL_A = LOOK.COL_A
This is what DimaSUN is doing in his query too -- but in his case he is creating the table dynamically in the body of the query.
Also note, I'm using a JOIN (which is an inner join) so only results in the lookup table will be returned. This could filter the results. A LEFT JOIN there would return all data from A but some of the new columns might be null.
Generally, a view is an instance of a table/a replica provided that there is no alteration to the original table. So, as per your query you can manipulate the data and columns in a view by using case.
Create View viewname as
Select *,
case when column=a.value then 'C'
....
ELSE
END
FROM ( Select * from table) a
If You have restricted list of replaced values You may hardcode that list in query
select T.*,map.New_Col
from ExistingTable T
left join (
values
('A','C')
,('B','D')
) map (Col_1,New_Col) on map.Col_1 = T.Col_1
In this sample You hardcode 'A' -> 'C' and 'B' -> 'D'
In general case You better may to use additional table ( see Hogan answer )

Is it possible to perform such a queries

I have SQL Server tables and I am supposed to create a query where it will be able to draw out the same data based on any combination of inputs of parameters / search conditions in a single query
For example, a user gives a model number for us to search for all products in table 1.
I would create a query as follows:
SELECT *
FROM Products
WHERE pModel = #pUserModel;
Next, another user gives us a description of the product which I then have to create another query as follows:
SELECT *
FROM Products
WHERE pDescription = #pUserDescription;
Table 1
Products (pNo, pModel, pDescription, pQty, pGlobalQty, pParent)
My issue here would be that instead of the two queries that were created based on different parameters, is there any way to create a single query where it will be able to fulfill those two search condition by both different users?
declare #pUserModel varchar(50)
declare #pUserDescription varchar(50)
--- if you want to search with individual search parameter than try with this.
if (#pUserModel <> '')
begin
SELECT * FROM Products WHERE pModel = #pUserModel;
end
else if (#pUserDescription <> '')
begin
SELECT * FROM Products WHERE pDescription = #pUserDescription;
end
--- if you want to combine all search parameter than try with this.
SELECT * FROM Products WHERE LTRIM(RTRIM(pModel)) = #pUserModel or LTRIM(RTRIM(pDescription)) = #pUserDescription
If I understand your requirement properly, you need join and OR condition
select * from Products p
left join Model m
on p.pModel=m.mModel
where (p.pModel = #pUserModel
OR p.pDescription = #pUserDescription)
Left join to return records from Products even if there is no Model associated with it. You can change it to INNER JOIN if you don't want it.
You can look for the trimmed length of the parameter string as part of an OR condition and always provide both parameters, even if one of them is an empty string "". Something like
SELECT
P.*
from
Products P
where
( LEN( RTRIM( #pUserModel )) = 0
OR P.pModel = #pUserModel )
OR
( LEN( RTRIM( #pUserDescription )) = 0
OR P.pDescription = #pUserDescription )
if you query such as where pDescription = '', it would fail if the description column actually HAS a value. So by wrapping each in an OR condition to say it's ok if the length of the TRIMMED parameter = 0 OR it matches the one being searched for. If you want the wild-card search, be sure to add '%'
To eliminate the OR qualifier, if your empty parameters are just '%', that will pull everything, for that respective parameters. So you could have a model = '%' and description = 'Something%'... Or vice-versa... Model = 'Some Model%' and Description = '%'
I aliased the products table as "P" to simplify readability. Especially if you have multiple tables, you should always identify where a table/column comes from for others to help.

'In' clause in SQL server with multiple columns

I have a component that retrieves data from database based on the keys provided.
However I want my java application to get all the data for all keys in a single database hit to fasten up things.
I can use 'in' clause when I have only one key.
While working on more than one key I can use below query in oracle
SELECT * FROM <table_name>
where (value_type,CODE1) IN (('I','COMM'),('I','CORE'));
which is similar to writing
SELECT * FROM <table_name>
where value_type = 1 and CODE1 = 'COMM'
and
SELECT * FROM <table_name>
where value_type = 1 and CODE1 = 'CORE'
together
However, this concept of using 'in' clause as above is giving below error in 'SQL server'
ERROR:An expression of non-boolean type specified in a context where a condition is expected, near ','.
Please let know if their is any way to achieve the same in SQL server.
This syntax doesn't exist in SQL Server. Use a combination of And and Or.
SELECT *
FROM <table_name>
WHERE
(value_type = 1 and CODE1 = 'COMM')
OR (value_type = 1 and CODE1 = 'CORE')
(In this case, you could make it shorter, because value_type is compared to the same value in both combinations. I just wanted to show the pattern that works like IN in oracle with multiple fields.)
When using IN with a subquery, you need to rephrase it like this:
Oracle:
SELECT *
FROM foo
WHERE
(value_type, CODE1) IN (
SELECT type, code
FROM bar
WHERE <some conditions>)
SQL Server:
SELECT *
FROM foo
WHERE
EXISTS (
SELECT *
FROM bar
WHERE <some conditions>
AND foo.type_code = bar.type
AND foo.CODE1 = bar.code)
There are other ways to do it, depending on the case, like inner joins and the like.
If you have under 1000 tuples you want to check against and you're using SQL Server 2008+, you can use a table values constructor, and perform a join against it. You can only specify up to 1000 rows in a table values constructor, hence the 1000 tuple limitation. Here's how it would look in your situation:
SELECT <table_name>.* FROM <table_name>
JOIN ( VALUES
('I', 'COMM'),
('I', 'CORE')
) AS MyTable(a, b) ON a = value_type AND b = CODE1;
This is only a good idea if your list of values is going to be unique, otherwise you'll get duplicate values. I'm not sure how the performance of this compares to using many ANDs and ORs, but the SQL query is at least much cleaner to look at, in my opinion.
You can also write this to use EXIST instead of JOIN. That may have different performance characteristics and it will avoid the problem of producing duplicate results if your values aren't unique. It may be worth trying both EXIST and JOIN on your use case to see what's a better fit. Here's how EXIST would look,
SELECT * FROM <table_name>
WHERE EXISTS (
SELECT 1
FROM (
VALUES
('I', 'COMM'),
('I', 'CORE')
) AS MyTable(a, b)
WHERE a = value_type AND b = CODE1
);
In conclusion, I think the best choice is to create a temporary table and query against that. But sometimes that's not possible, e.g. your user lacks the permission to create temporary tables, and then using a table values constructor may be your best choice. Use EXIST or JOIN, depending on which gives you better performance on your database.
Normally you can not do it, but can use the following technique.
SELECT * FROM <table_name>
where (value_type+'/'+CODE1) IN (('I'+'/'+'COMM'),('I'+'/'+'CORE'));
A better solution is to avoid hardcoding your values and put then in a temporary or persistent table:
CREATE TABLE #t (ValueType VARCHAR(16), Code VARCHAR(16))
INSERT INTO #t VALUES ('I','COMM'),('I','CORE')
SELECT DT. *
FROM <table_name> DT
JOIN #t T ON T.ValueType = DT.ValueType AND T.Code = DT.Code
Thus, you avoid storing data in your code (persistent table version) and allow to easily modify the filters (without changing the code).
I think you can try this, combine and and or at the same time.
SELECT
*
FROM
<table_name>
WHERE
value_type = 1
AND (CODE1 = 'COMM' OR CODE1 = 'CORE')
What you can do is 'join' the columns as a string, and pass your values also combined as strings.
where (cast(column1 as text) ||','|| cast(column2 as text)) in (?1)
The other way is to do multiple ands and ors.
I had a similar problem in MS SQL, but a little different. Maybe it will help somebody in futere, in my case i found this solution (not full code, just example):
SELECT Table1.Campaign
,Table1.Coupon
FROM [CRM].[dbo].[Coupons] AS Table1
INNER JOIN [CRM].[dbo].[Coupons] AS Table2 ON Table1.Campaign = Table2.Campaign AND Table1.Coupon = Table2.Coupon
WHERE Table1.Coupon IN ('0000000001', '0000000002') AND Table2.Campaign IN ('XXX000000001', 'XYX000000001')
Of cource on Coupon and Campaign in table i have index for fast search.
Compute it in MS Sql
SELECT * FROM <table_name>
where value_type + '|' + CODE1 IN ('I|COMM', 'I|CORE');

Writing a single UPDATE statement that prevents duplicates

I've been trying for a few hours (probably more than I needed to) to figure out the best way to write an update sql query that will dissallow duplicates on the column I am updating.
Meaning, if TableA.ColA already has a name 'TEST1', then when I'm changing another record, then I simply can't pick a value for ColA to be 'TEST1'.
It's pretty easy to simply just separate the query into a select, and use a server layer code that would allow conditional logic:
SELECT ID, NAME FROM TABLEA WHERE NAME = 'TEST1'
IF TableA.recordcount > 0 then
UPDATE SET NAME = 'TEST1' WHERE ID = 1234
END IF
But I'm more interested to see if these two queries can be combined into a single query.
I am using Oracle to figure things out, but I'd love to see a SQL Server query as well. I figured a MERGE statement can work, but for obvious reasons you can't have the clause:
..etc.. WHEN NOT MATCHED UPDATE SET ..etc.. WHERE ID = 1234
AND you can't update a column if it's mentioned in the join (oracle limitation but not limited to SQL Server)
ALSO, I know you can put a constraint on a column that prevents duplicate values, but I'd be interested to see if there is such a query that can do this without using constraint.
Here is an example start-up attempt on my end just to see what I can come up with (explanations on it failed is not necessary):
ERROR: ORA-01732: data manipulation operation not legal on this view
UPDATE (
SELECT d.NAME, ch.NAME FROM (
SELECT 'test1' AS NAME, '2722' AS ID
FROM DUAL
) d
LEFT JOIN TABLEA a
ON UPPER(a.name) = UPPER(d.name)
)
SET a.name = 'test2'
WHERE a.name is null and a.id = d.id
I have tried merge, but just gave up thinking it's not possible. I've also considered not exists (but I'd have to be careful since I might accidentally update every other record that doesn't match a criteria)
It should be straightforward:
update personnel
set personnel_number = 'xyz'
where person_id = 1001
and not exists (select * from personnel where personnel_number = 'xyz');
If I understand correctly, you want to conditionally update a field, assuming the value is not found. The following query does this. It should work in both SQL Server and Oracle:
update table1
set name = 'Test1'
where (select count(*) from table1 where name = 'Test1') > 0 and
id = 1234