Using Index for joining two tables when FK field is NULL - sql

We started to maintain a new project that uses SQL Server and there are some problems regarding to the data in some tables as explained below. There are 2 tables called Employee and Pass and the Pass table keeps the in and out of every Employee.
Employee
|| ID || Name || CardNo ||
======================================
|| 1 || John || 101 ||
|| 2 || Christof || 102 ||
|| 3 || Jurgen || 103 ||
|| 4 || Jose || 104 ||
|| 5 || Mary || 105 ||
Pass
|| ID || EmployeeID || CardNo ||
======================================
|| 1 || NULL || 101 ||
|| 2 || NULL || 105 ||
|| 3 || NULL || 103 ||
|| 4 || NULL || 101 ||
|| 5 || NULL || 102 ||
|| 6 || NULL || 104 ||
|| 7 || NULL || 104 ||
|| 8 || NULL || 103 ||
|| 9 || NULL || 105 ||
|| 10 || NULL || 101 ||
On the other hand, as the EmployeeID column of the Pass table is empty for every pass, we have to use CardNo column in order to join two tables.
But using the JOIN clause as shown below causes the query to be executed more time and I think there might be a better way by using index, etc. instead of PK to optimize the query. We have tried to create index, but could not create for CardNo column.
Could you please clarify us on how to fix the problem? Thanks...
SELECT *
FROM Pass p
LEFT JOIN Employee e ON RIGHT(e.CardNo, 8) = RIGHT(p.CardNo, 8) --I have to trim card no as the digit sizes are different
Update :
I tried to apply the following scripts, but only this part is worked:
alter table Pass add cardno8 as RIGHT(CardNo, 8);
alter table Employee add cardno8 as RIGHT(CardNo, 8);
And this part gives error: "Column 'cardno8' in table 'Pass' is of a type that is invalid for use as a key column in an index."
create index idx_tEvent_cardno8 ON Pass(cardno8);
create index idx_tEmployee_cardno8 ON Employee (cardno8);
Any idea?

If the problem is the performance of the query, then you simply need an index on Employee(CardNo):
create index idx_employee_cardno on employee(cardno);
If you are interested in only one or two other columns (such as name or id), you can add them to the index after cardno.
The only reason that I can think of (apart from permissions) to explain why index creation would fail is that cardno has the wrong type. To quote the documentation:
Columns that are of the large object (LOB) data types ntext, text,
varchar(max), nvarchar(max), varbinary(max), xml, or image cannot be
specified as key columns for an index.
That seems unlikely given the sample data. If this is an issue, then change the type to something more appropriate (or use a computed column for the same purpose).
Also, your query should use qualified column names everywhere (or you'll get an error):
SELECT *
FROM Pass p LEFT JOIN
Employee e
ON e.CardNo = p.CardNo;
--------^

Related

How to concatenate multiple columns where value may be be NULL

I need to pull a query from multiple columns from a table. Some rows will have data in one column, others will have two, three, and even four.
I tried to use this construct:
SELECT person_uid,('(' || major || NVL((',' ||second_major), '') || NVL((',' ||third_major), '') || NVL(',' ||fourth_major, '') || ')' ) AS MAJORS FROM academic_study
But the result would be like this:
6231 (BUMG,BUMK,,)
19091 (TDST,TDPG,,)
I need the parentheses, but not the trailing commas.
I could potentially strip out the extra commas in post processing, but I would prefer to do it in the SQL. I am using ORACLE.
You should fix your data model! Storing multiple columns with parallel data is awkward.
One method is:
select person_uid,
( '(' || major ||
(case when second_major is not null then ',' || second_major end) ||
(case when third_major is not null then ',' || third_major end) ||
(case when fourth_major is not null then ',' || fourth_major end) ||
')'
)

How do I make a select statement for the following question?

Sorry for asking a simple question but how do you create this Select statement and what is your thought process?
I've listed down the following table that I think is needed for this select statement.
Question: Create a SELECT statement to display a listing of the number of times of the service
requested from each staff. Display staff id, staff’s name, service_no, service’s
description and a total number of times requested.
Table: SERVICES
Column Name || Constraints || Default Value || Data Type || Length
SERVICE_NO || Primary Key || || VarChar2 || 10
DESCRIPTION || || || VarChar2 || 50
CONTRACTOR || || || VarChar2 || 20
CCONTACT_NO || || || VarChar2 || 10
Table: SERVICE_REQUEST
Column Name || Constraints || Default Value || Data Type || Length
SR_ID || Primary Key || || Number || 10
SERVICE_NO || Foreign Key to the SERVICES table || || VarChar2 || 10
STAFF_ID || Foreign Key to the STAFF table || || VarChar2 || 10
TEC_ID || Foreign Key to the TECHNICIANS table || || VarChar2 || 10
REQUEST_DATE || || || Date ||
REQUEST_TIME || || || VarChar2 || 10
Table: STAFF
Column Name || Constraints || Default Value || Data Type || Length
STAFF_ID || Primary key || || VarChar2 || 10
SNAME || || || VarChar2 || 30
SIC_NO || Secondary key || || VarChar2 || 10
SADDRESS || || || VarChar2 || 70
SPHONE || || || VarChar2 || 8
POSITION || || || VarChar2 || 30
HIRE_DATE || || || Date ||
SALARY || || || Number || 7,2
SCH_ID || Foreign Key to the SCHOOL table || || VarChar2 || 10
Use the query.
select s.staff_id,
s.sname,
ser.service_no,
ser.description,
(select count(service_no) from staff where service_no = ser )
from service_request sr ,services ser
where s.staff_id = sr.staff_id
and ser.service_no = sr.service_no;

How to update a column with different value using simple Join statement?

I have two tables and i am using a simple join condition between them.
I need to find the common values and updated the String(Success) into the column.
input_table1:
ID || Name || output
1 || ABS || Null
2 || ADF || NULL
3 || AQS || Null
4 || ATF || NULL
5 || APS || Null
6 || AMF || NULL
Input_table2:
ID || Name
1 || ABS
2 || ADF
6 || AMF
Output_table:This is the output I need.
ID || Name || output
1 || ABS || Success
2 || ADF || Success
3 || AQS || Null
4 || ATF || NULL
5 || APS || Null
6 || AMF || Success.
This is the query i am using and this is the error is am receiving
An expression of non-boolean type specified in a context where a condition is expected, near 'Then'.
update .[dbo].[InputTable1]
set Output=
case when (
select INT.ID
from [dbo].[input_table1] INT
join [dbo].[input_table2] SHB
on INT.ID=SHB.ID
) Then 'Success' Else Null End
your query should simply be
update INT
set Output= 'Success'
FROM
[dbo].[input_table1] INT
join [dbo].[input_table2] SHB
on INT.ID=SHB.ID
See working demo
...CASE WHEN <condition> = <value> THEN....
You are missing <value> I suspect you need IS NOT NULL after your query.
That said, it is not efficient. DhruvJoshi is better
I would use EXISTS and FROM behind UPDATE for that
UPDATE it
SET Output = (CASE WHEN exists(
SELECT 1
FROM [dbo].[input_table2] SHB
WHERE it.ID=SHB.ID)
THEN 'Success' ELSE Null END)
FROM [dbo].[InputTable1] it
You can just try this :
UPDATE
InputTable1
SET
Output='Success'
FROM
InputTable1
JOIN InputTable2 ON
InputTable1.ID=InputTable2.ID
Only joined rows will be updated

oracle insert using DBlink

I have two different databases, say DB1 and DB2. In both DBs I have a common table called test_emp, but there is a difference in the columns of the tables:
DB1
-----
desc table1
--------------
empno number
ename varchar2
sal number
hiredate date
deptno number
DB2
-----
desc table2
--------------
empno number
ename varchar2
sal number
insert into table1 select * from table2#DBLink_Name
But here I have a problem with number of columns, target table has more columns than the source.
Here I can't specify column_names because I am passing table as dynamic.
Can you somebody please help?
You could look at the oracle data dictionary/metadata tables on both databases and generate the necessary sql for the insert. if i_table_name is your input.
select list_agg(column_name,',') columns -- comma separated list of columns
from (
select column_name
from all_tab_cols
where owner = 'XYZ'
and table_name = i_table_name
intersect
select column_name
from all_tab_cols#remote_database
where owner = 'XYZ' -- could be different (?)
and table_name = i_table_name
)
You could then use this string (comma separated list of colums) to do something along the lines of..
v_sql := 'insert into ' || i_table_name || ' ' || '(' ||
v_column_list || ')' ||
' select ' || '( ' || v_column_list ||
' from ' || i_table_name || '#' || remote_db_name;
dbms_output.put_line(v_sql);
execute immediate v_sql;
I haven't tested the code. Make sure you print the insert and confirm it matches your expectations.
use
INSERT INTO table1
SELECT a.*,
NULL,
NULL
FROM table2#dblink_

format column headers during concat,oracle

I need to format column headers in the output of sql while using concat
Eg:
SELECT '' || to_char(sysdate,'ddmmyyyy') as DATE || ',' || ENO|| ',' || NAME|| ''
FROM EMP;
would retrieve me
ORA-00923: FROM keyword not found where expected.
Need the output as:
DATE ENO NAME
-----------------
251013 7560 RAM
251013 7561 ROSS
This format works
SELECT to_char(sysdate,'ddmmyyyy') || ',' || ENO || ',' || NAME as "DATE,ENO,NAME"
FROM EMP
but I have an issue with
ORA-00972: identifier is too long
when the length of column names inside as "" exceeds 30 characters
Eg:
SELECT to_char(sysdate,'ddmmyyyy') || ',' || ENO || ',' || NAME ||
',' || EMPLOYEE_IDENTIFICATION_NUMBER as "DATE,ENO,NAME,EMPLOYEE_IDENTIFICATION_NUMBER"
FROM EMP;
To achieve this output you have to build your query like this
SELECT to_char(sysdate,'ddmmyyyy') || ',' || ENO || ',' || NAME as "DATE,ENO,NAME" FROM EMP
You need to move the alias, if you really need it, at the end of the SELECT clause. Also the empty strings ('') can be removed:
SELECT to_char(sysdate,'ddmmyyyy') || ',' || ENO || ',' || NAME as DATE FROM EMP;