SQL Server 2014: Either selected or all values in where condition - sql

Below is what I am trying to achieve. I have a procedure which receives employeeIds as optional arguments and stores them into a temp table (temp_table) like this
empId
-------
3432
3255
5235
2434
Now I need to run below query in 2 conditions:
1st condition: if argument is non blank then my query should be-
SELECT *
FROM DEPARTMENTS
INNER JOIN temp_table ON emp_no = empId
2nd condition: if argument is blank it will take all the rows from department table
SELECT *
FROM DEPARTMENTS
One option I can use is:
IF (#args <> '')
BEGIN
SELECT *
FROM DEPARTMENTS
INNER JOIN temp_table ON emp_no = empId
END
ELSE
BEGIN
SELECT *
FROM DEPARTMENTS
END
But I am looking for a better option where I don't need to write almost same query twice. Please help.

I recommend to stick to what you are already doing.
It is the cleanest and safest way performance wise.

Try this one
SELECT *
FROM DEPARTMENTS
WHERE (
#args <> ''
OR EXISTS (SELECT 1 FROM temp_table WHERE emp_no = empId)
)

Related

Microsoft SQL Server - Convert column values to list for SELECT IN

I have this (3 int columns in one table)
Int1 Int2 Int3
---------------
1 2 3
I would like to run such query with another someTable:
SELECT * FROM someTable WHERE someInt NOT IN (1,2,3)
where 1,2,3 are list of INTs converted to a list that I can use with SELECT * NOT IN statement
Any suggestions how to achieve this without stored procedures in Micorosft SQL Server 2019 ?
If you want rows in some table that are not in one of three columns of another table, then use not exists:
select t.*
from sometable t
where not exists (select 1
from t t2
where t.someint in (t2.int1, t2.int2, t2.int3)
);
The subquery returns a row where there is a match. The outer query then rejects any rows with a match.
Seems like you actually want a NOT EXISTS?
SELECT {Your Columns}
FROM dbo.someTable sT
WHERE NOT EXISTS (SELECT 1
FROM dbo.oneTable oT
WHERE sT.someInt NOT IN (oT.int1,oT.int2,oT.int3));
An alternative method would be to unpivot the data, and then use an equality operator:
SELECT {Your Columns}
FROM dbo.someTable sT
WHERE NOT EXISTS (SELECT 1
FROM dbo.oneTable oT
CROSS APPLY (VALUES(oT.int1),(oT.int2),(oT.int3))V(I)
WHERE V.I = sT.someInt);

Pivot top 100 rows into columns for all tables in a database

My mission is to get top 100 rows from all my tables in a database, and union them into one result output.
Since the tables have varying columncount and varying types, the only way I see to do this is to put the row number as columns, and the column name in the first column. Row 1 from all tables will then be represented in column 2 and so forth.
My skills in SQL aren't good enough to figure this one out, so I hope the community can assist me in this.
Here is some code:
--Example table
create table Worker (Id int, FirstName nvarchar(max));
--Some data
insert into Worker values (1,'John'),(2,'Jane'),(3,'Elisa');
--Static pivot example
select * from (select
ROW_NUMBER() over (order by Id) as IdRows, FirstName from worker) as st
pivot
(
max(FirstName) for IdRows in ([1],[2],[3])
) as pt;
--Code to incorporate to get column name on column 1
select name from sys.columns where object_id('Worker') = object_id;
--Cleanup
drop table Worker;
I reckon the static pivot must be dynamic, which is not a problem. The above code is just to create a proof of concept, so I have something to build further on.
End result of query should be like this:
Column 1 2 3
FirstName John Erina Jane
I hope this can be solved without using cursors and temp tables, but maybe that's the way to go?
EDIT:
Forgot to mention, I'm using sqlserver (mssql)
EDIT2:
I'm not all that good at explaining, so here is some more code to do that job for me.
This will add another column to Worker table, and a query to show the desired result. It's the query that has to be "smarter" so it can handle future added tables and columns added. (again, this is a proof of concept. The database has > 200 tables and > 1000 columns)
--Add a column
alter table Worker add LastName nvarchar(max);
--Add some data
update Worker set LastName = 'Smith' where Id = 1;
update Worker set LastName = 'Smith' where Id = 2;
update Worker set LastName = 'Smith' where Id = 3;
--Query to give desired output (top 100, but only 3 rows in this table)
select 'FirstName' as 'Column',* from (select top 100
ROW_NUMBER() over (order by Id) as IdRows, FirstName from worker) as st
pivot
(
max(FirstName) for IdRows in ([1],[2],[3])
) as pt
union
select 'LastName' as 'Column',* from (select top 100
ROW_NUMBER() over (order by Id) as IdRows, LastName from worker) as st
pivot
(
max(LastName) for IdRows in ([1],[2],[3])
) as pt
To solve this, I used temp table, and put it into a loop. Not a good solution, but it works. Had to cast all the data to nvarchar to make it work.

how to update multiple rows in oracle

I would like to update multiple rows with different values for all different records, but don't have any idea how to do that, i am using below sql to update for single record but i have 200 plus records to update
update employee
set staff_no = 'ab123'
where depno = 1
i have 50 dep and within those dep i need to update 200 plus staff no. any idea.
At the moment if i just do a
select * from Departments
i can see list of all employee which needs staff no updating.
UPDATE person
SET staff_no =
CASE person_no
WHEN 112 THEN 'ab123'
WHEN 223 THEN 'ab324'
WHEN 2343 THEN 'asb324'
and so on.....
END
You should be able to use MERGE statement to do it in a single shot. However, the statement is going to be rather large:
MERGE INTO employee e
USING (
SELECT 1 as d_id, 'cd234' as staff_no FROM Dual
UNION ALL
SELECT 2 as d_id, 'ef345' as staff_no FROM Dual
UNION ALL
SELECT 3 as d_id, 'fg456' as staff_no FROM Dual
UNION ALL
... -- More selects go here
SELECT 200 as d_id, 'za978' as staff_no FROM Dual
) s
ON (e.depno = S.d_id)
WHEN MATCHED THEN UPDATE SET e.staff_no= s.staff_no
use a case expression
UPDATE employee
SET staff_no =
CASE depno
WHEN 1 THEN 'ab123'
WHEN 2 THEN 'ab321'
--...
ELSE staff_no
END
WHERE depno IN ( 1, 2 ) -- list all cases here. use a subquery if you don't want to / cannot enumerate
For conditional update, you could use multiple update statements, or use CASE expression in the SET clause.
Something like,
UPDATE table
SET schema.column = CASE
WHEN column1= 'value1' AND column2='value2' THEN
'Y'
ELSE
'N'
END
I wish you tried to search for a similar question on this site, there was a recent question and this was my answer.
If you have two tables like:
CREATE TABLE test_tab_1 (id NUMBER, name VARCHAR2(25));
CREATE TABLE test_tab_2 (id NUMBER, name VARCHAR2(25));
You can use UPDATE statement as below:
UPDATE test_tab_1
SET test_tab_1.name = (SELECT test_tab_2.name FROM test_tab_2
WHERE test_tab_1.id = test_tab_2.id);

PL/SQL Oracle Query With IF Statement

I want to implement a query that only returns the logged in user and displays there record only, which I have done as follows and it works:
SELECT * FROM EMPLOYEE
WHERE UPPER(username) = v('APP_USER')
However, I have another column called User_Type, and a user can be type 1, 2 or 3. If I have a user type of 1, I want the query to also return all the tables records too as user type 1 is an admin.
I thought about doing it like this:
BEGIN
SELECT * FROM Employee
WHERE upper(username) = v('APP_USER')
IF User_Type = 1
THEN SELECT * FROM Employee
END IF;
END;
/
But it doesn't work in APEX Oracle PLSQL.
Any suggestions?
From what I understand you need to try this:
DECLARE
emp employee%ROWTYPE; -- Create a record type
tbl_emp IS TABLE OF emp;
-- ^^^ Create a table of that record type
v_user_type employee.user_type%TYPE;
-- ^^^ Variable to store user type
BEGIN
SELECT user_type
INTO v_user_type
FROM Employee
WHERE upper(username) = v('APP_USER');
IF v_user_type = 1 THEN
SELECT *
BULK COLLECT INTO tbl_emp
FROM employee;
-- ^^ Returns the entire table
ELSE
SELECT *
BULK COLLECT INTO tbl_emp
FROM employee;
WHERE upper(username) = v('APP_USER');
-- ^^ Returns the row related to the user.
END IF;
END;
/
The output is stored in the nested table variable tbl_emp.
EDIT:
It can be achieved using pure SQL also, like this:
SELECT *
FROM employee e
WHERE EXISTS (SELECT 1
FROM employees e_in
WHERE e_in.user_type = 1
AND UPPER(e_in.username) = v('APP_USER'))
OR UPPER(e.username) = v('APP_USER')
Choose whichever is best suited for you.
You want all records from users with either UPPER(username) being v('APP_USER') or User_Type being 1? Then just use OR:
SELECT * FROM Employee WHERE upper(username) = v('APP_USER') OR User_Type = 1
If that's not what you mean, then can you explain more clearly?
Try:
select distinct e2.*
from employee e1
join employee e2 on (e1.username = e2.username or e1.User_Type = 1)
where UPPER(e1.username) = v('APP_USER')

Count(*) with 0 for boolean field

Let's say I have a boolean field in a database table and I want to get a tally of how many are 1 and how many are 0. Currently I am doing:
SELECT 'yes' AS result, COUNT( * ) AS num
FROM `table`
WHERE field = 1
UNION
SELECT 'no' AS result, COUNT( * ) AS num
FROM `table`
WHERE field = 0;
Is there an easier way to get the result so that even if there are no false values I will still get:
----------
|yes | 3 |
|no | 0 |
----------
One way would be to outer join onto a lookup table. So, create a lookup table that maps field values to names:
create table field_lookup (
field int,
description varchar(3)
)
and populate it
insert into field_lookup values (0, 'no')
insert into field_lookup values (1, 'yes')
now the next bit depends on your SQL vendor, the following has some Sybase (or SQL Server) specific bits (the outer join syntax and isnull to convert nulls to zero):
select description, isnull(num,0)
from (select field, count(*) num from `table` group by field) d, field_lookup fl
where d.field =* fl.field
you are on the right track, but the first answer will not be correct. Here is a solution that will give you Yes and No even if there is no "No" in the table:
SELECT 'Yes', (SELECT COUNT(*) FROM Tablename WHERE Field <> 0)
UNION ALL
SELECT 'No', (SELECT COUNT(*) FROM tablename WHERE Field = 0)
Be aware that I've checked Yes as <> 0 because some front end systems that uses SQL Server as backend server, uses -1 and 1 as yes.
Regards
Arild
This will result in two columns:
SELECT SUM(field) AS yes, COUNT(*) - SUM(field) AS no FROM table
Because there aren't any existing values for false, if you want to see a summary value for it - you need to LEFT JOIN to a table or derived table/inline view that does. Assuming there's no TYPE_CODES table to lookup the values, use:
SELECT x.desc_value AS result,
COALESCE(COUNT(t.field), 0) AS num
FROM (SELECT 1 AS value, 'yes' AS desc_value
UNION ALL
SELECT 2, 'no') x
LEFT JOIN TABLE t ON t.field = x.value
GROUP BY x.desc_value
SELECT COUNT(*) count, field FROM table GROUP BY field;
Not exactly same output format, but it's the same data you get back.
If one of them has none, you won't get that rows back, but that should be easy enough to check for in your code.