How to replace the IN operator with EXISTS operator, for the where clause part of the query? - sql

WHERE (
((SERVICECOMPONENT_ID IN (123, 150, 198, 199, 290, 287, 291, 289, 288, 286, 282, 281)))
OR ((SERVICEREQUEST_ID IN (
SELECT distinct(SR.SERVICEREQUEST_ID)
FROM SERVICE_REQUEST SR,ASSIGNED_SR_PROJECTS ASP,PROJECT_RESOURCES PRS
WHERE SR.SERVICEREQUEST_ID = ASP.SERVICEREQUEST_ID
AND PRS.PROJECT_ID = ASP.PROJECT_ID
AND PRS.RESPONSIBILITY IN ('MANAGER','LEAD')
AND PRS.RESOURCE_ID =180 )) )
)

In general,
SELECT a FROM b WHERE c IN (SELECT d FROM e)
is equivalent to
SELECT a FROM b WHERE EXISTS (SELECT 1 FROM e WHERE c = d)
The SERVICEREQUEST_ID IN (subquery) part of your code example translates to:
OR EXISTS (
SELECT 1
FROM
SERVICE_REQUEST SR,
ASSIGNED_SR_PROJECTS ASP,
PROJECT_RESOURCES PRS
WHERE
SR.SERVICEREQUEST_ID = ASP.SERVICEREQUEST_ID
AND PRS.PROJECT_ID = ASP.PROJECT_ID
AND PRS.RESPONSIBILITY IN ('MANAGER', 'LEAD')
AND PRS.RESOURCE_ID = 180
AND mytable.SERVICEREQUEST_ID = SR.SERVICEREQUEST_ID
)

if you have static list of elements It's better to use "IN".... If you have a subquery and it is returning more than one value then Use Exist...
There is no Difference in Both clauses..
WHERE (
( (SERVICECOMPONENT_ID IN ( 123 , 150 , 198 , 199 , 290 , 287 , 291 , 289 , 288 , 286 , 282 , 281 )) )
OR ( (SERVICEREQUEST_ID IN ( 1952 , 2387 , 3618 , 3633 , 4178 , 4432 , 5090 , 5271 , 6068 , 6320 , 6396 , 6526 , 7162 , 7442 , 7558 , 7639 , 7688 , 8176 , 8189 , 8338 , 8460 , 8461 , 8598 , 8612 , 8628 , 8675 , 8775 , 8869 , 8886 , 8898 )) )
OR ( (REQUESTED_BY LIKE 'XXXXXXX#example.com' ) )
OR ( ( EXISTS ( SELECT count(distinct(SR.SERVICEREQUEST_ID)) FROM SERVICE_REQUEST SR,ASSIGNED_SR_PROJECTS ASP,PROJECT_RESOURCES PRS WHERE SR.SERVICEREQUEST_ID = ASP.SERVICEREQUEST_ID AND PRS.PROJECT_ID = ASP.PROJECT_ID AND PRS.RESPONSIBILITY IN ('MANAGER','LEAD') AND PRS.RESOURCE_ID =180 )) )
OR ( (STATUS_CODE LIKE 'OPEN' ) AND ( EXISTS (SELECT count(COMPONENT.CATEGORY_ID) FROM PROJECTMASTER PROJECTS, BUDGET BUDGET, CONTRACT CONTRACT,COMPONENTS COMPONENT, PROJECT_RESOURCES PROJ_RESOURCES, CATEGORY_OWNER_ASSIGNMENT CATEGORYOWNER, SERVICECATEGORYASSIGNMENT CATEGORYASSIGNMENT WHERE PROJECTS.PROJECT_ID = PROJ_RESOURCES.PROJECT_ID AND PROJECTS.BUDGET_ID = BUDGET.BUDGET_ID AND BUDGET.CONTRACT = CONTRACT.CONTRACT_ID AND CATEGORYASSIGNMENT.CONTRACT_ID = CONTRACT.CONTRACT_ID AND COMPONENT.COMPONENT_ID = CATEGORYASSIGNMENT.COMPONENT_ID AND CATEGORYOWNER.CATEGORY_ID = COMPONENT.CATEGORY_ID AND CATEGORYOWNER.USER_ID = PROJ_RESOURCES.RESOURCE_ID AND (CATEGORYOWNER.OWNER_FLAG = 'Y' OR CATEGORYOWNER.MEMBER_FLAG = 'Y') AND PROJ_RESOURCES.RESOURCE_ID = 180 AND PROJ_RESOURCES.ACTIVE_FLAG = 'Y' AND CATEGORYASSIGNMENT.ACTIVE_FLAG = 'Y' AND PROJ_RESOURCES.RESPONSIBILITY IN ('MANAGER', 'LEAD') )) )
)
read this for further clarification..
Difference between EXISTS and IN in SQL?

Related

SQL Query simplification, really slow query 1-2 mins

How do I even get start on trying to simplify this mess? It takes such a long time like 1-2 minutes query. I even made a graph structure to see it better (see below). I would really appreciate all the help. I think the nested unions or the "where (0=1)" are making it really slow, but this query currently holds all the data we need.
SELECT
DISTINCT LB_ID,
LB_KLASGROEP_FK,
PL_ID,
BO_ID,
BO_TYPE,
BO_BEOORDELINGMOMENT_FK,
BO_VAKBEOORDELING_FK,
BO_BEOORDELINGBEREKENING_FK,
BB_TYPE_FKP,
BB_FLAGS,
BB_EVALUATIEVERWIJZING_FK,
BB_CATEGORIE_FK,
VB_TYPE_FKP,
VB_EVALUATIEVERWIJZING_FK,
BW_ID,
BW_TYPE,
BW_NUMERIEK,
BW_COMMENTAAR,
BW_AFWEZIG,
BW_LIJSTELEMENT_FK,
QLE_CODE,
EV_TYPE,
EV_DAGELIJKSWERK_FK,
EV_EXAMEN_FK,
EV_PERIODEEVALUATIE_FK,
EV_JAAREVALUATIE_FK,
IV_ID,
VB_QUOTATIELIJST_FK
FROM
PUNTENBLAD
LEFT JOIN (
SELECT
PL_ID AS PLLB_PUNTENBLAD_FK,
LB_ID AS PLLB_LOOPBAAN_FK
FROM
PUNTENBLAD
LEFT JOIN LESGROEPDETAILS ON (PL_LESGROEP_FK = LSD_LESGROEP_FK)
LEFT JOIN KLAS ON (
(PL_KLAS_FK = KL_ID)
OR (
(LSD_TYPEGROEPDEEL = 0)
AND (LSD_GROEPDEEL_FK = KL_ID)
)
)
LEFT JOIN KLASGROEP ON (
(PL_KLASGROEP_FK = KG_ID)
OR (KL_ID = KG_KLAS_FK)
OR (
(LSD_TYPEGROEPDEEL = 1)
AND (LSD_GROEPDEEL_FK = KG_ID)
)
)
LEFT JOIN LOOPBAANLESEENHEID ON (
(
PL_LESEENHEID_FK = LH_LESEENHEID_FK
)
OR (
(LSD_TYPEGROEPDEEL = 2)
AND (
LSD_GROEPDEEL_FK = LH_LESEENHEID_FK
)
)
)
LEFT JOIN LOOPBAAN ON (
(KG_ID = LB_KLASGROEP_FK)
OR (LH_LOOPBAAN_FK = LB_ID)
)
) AS PUNTENBLADLOOPBAAN ON (PL_ID = PLLB_PUNTENBLAD_FK)
INNER JOIN LOOPBAAN ON (PLLB_LOOPBAAN_FK = LB_ID)
LEFT JOIN KLASGROEP ON (LB_KLASGROEP_FK = KG_ID)
LEFT JOIN KLAS ON (KG_KLAS_FK = KL_ID)
LEFT JOIN INUIT ON (LB_INUIT_FK = IU_ID)
LEFT JOIN LEERLING ON (IU_LEERLING_FK = LL_ID)
LEFT JOIN (
SELECT
BM_PUNTENBLAD_FK AS BO_PUNTENBLAD_FK,
BO_ID,
BO_TYPE,
BO_BEOORDELINGMOMENT_FK,
BO_VAKBEOORDELING_FK,
BO_BEOORDELINGBEREKENING_FK,
EV_ID,
BM_CODE,
BM_OMSCHRIJVING,
BM_DATUM,
BM_NOEMER,
BM_GEWICHT,
BM_GEWENST,
BM_TYPE,
BM_EVALUATIEVERWIJZING_FK,
BM_PUBLICATIEDATUM,
BM_CATEGORIE_FK,
BM_QUOTATIELIJST_FK,
NULL AS VB_CODE,
NULL AS VB_OMSCHRIJVING,
NULL AS VB_QUOTATIELIJST_FK,
NULL AS VB_TYPE_FKP,
NULL AS VB_EVALUATIEVERWIJZING_FK,
NULL AS BB_CODE,
NULL AS BB_OMSCHRIJVING,
NULL AS BB_TYPE_FKP,
NULL AS BB_FLAGS,
NULL AS BB_EVALUATIEVERWIJZING_FK,
NULL AS BB_CATEGORIE_FK,
NULL AS BB_NEEDSRECALCULATION
FROM
BEOORDELINGMOMENT
LEFT JOIN BEOORDELING ON (BM_ID = BO_BEOORDELINGMOMENT_FK)
LEFT JOIN EVALUATIEVERWIJZING ON (
BM_EVALUATIEVERWIJZING_FK = EV_ID
)
WHERE
(0 = 1)
UNION
SELECT
VB_PUNTENBLAD_FK AS BO_PUNTENBLAD_FK,
BO_ID,
BO_TYPE,
BO_BEOORDELINGMOMENT_FK,
BO_VAKBEOORDELING_FK,
BO_BEOORDELINGBEREKENING_FK,
EV_ID,
NULL AS BM_CODE,
NULL AS BM_OMSCHRIJVING,
NULL AS BM_DATUM,
NULL AS BM_NOEMER,
NULL AS BM_GEWICHT,
NULL AS BM_GEWENST,
NULL AS BM_TYPE,
NULL AS BM_EVALUATIEVERWIJZING_FK,
NULL AS BM_PUBLICATIEDATUM,
NULL AS BM_CATEGORIE_FK,
NULL AS BM_QUOTATIELIJST_FK,
VB_CODE,
VB_OMSCHRIJVING,
VB_QUOTATIELIJST_FK,
VB_TYPE_FKP,
VB_EVALUATIEVERWIJZING_FK,
NULL AS BB_CODE,
NULL AS BB_OMSCHRIJVING,
NULL AS BB_TYPE_FKP,
NULL AS BB_FLAGS,
NULL AS BB_EVALUATIEVERWIJZING_FK,
NULL AS BB_CATEGORIE_FK,
NULL AS BB_NEEDSRECALCULATION
FROM
VAKBEOORDELING
LEFT JOIN BEOORDELING ON (VB_ID = BO_VAKBEOORDELING_FK)
LEFT JOIN EVALUATIEVERWIJZING ON (
VB_EVALUATIEVERWIJZING_FK = EV_ID
)
UNION
SELECT
BB_PUNTENBLAD_FK AS BO_PUNTENBLAD_FK,
BO_ID,
BO_TYPE,
BO_BEOORDELINGMOMENT_FK,
BO_VAKBEOORDELING_FK,
BO_BEOORDELINGBEREKENING_FK,
EV_ID,
NULL AS BM_CODE,
NULL AS BM_OMSCHRIJVING,
NULL AS BM_DATUM,
NULL AS BM_NOEMER,
NULL AS BM_GEWICHT,
NULL AS BM_GEWENST,
NULL AS BM_TYPE,
NULL AS BM_EVALUATIEVERWIJZING_FK,
NULL AS BM_PUBLICATIEDATUM,
NULL AS BM_CATEGORIE_FK,
NULL AS BM_QUOTATIELIJST_FK,
NULL AS VB_CODE,
NULL AS VB_OMSCHRIJVING,
NULL AS VB_QUOTATIELIJST_FK,
NULL AS VB_TYPE_FKP,
NULL AS VB_EVALUATIEVERWIJZING_FK,
BB_CODE,
BB_OMSCHRIJVING,
BB_TYPE_FKP,
BB_FLAGS,
BB_EVALUATIEVERWIJZING_FK,
BB_CATEGORIE_FK,
BB_NEEDSRECALCULATION
FROM
BEOORDELINGBEREKENING
LEFT JOIN BEOORDELING ON (
BB_ID = BO_BEOORDELINGBEREKENING_FK
)
LEFT JOIN EVALUATIEVERWIJZING ON (
BB_EVALUATIEVERWIJZING_FK = EV_ID
)
) AS BEOORDELINGEN ON (PL_ID = BO_PUNTENBLAD_FK)
LEFT JOIN BEOORDELINGWAARDE ON (
(LB_ID = BW_LOOPBAAN_FK)
AND (
BEOORDELINGEN.BO_ID = BW_BEOORDELING_FK
)
)
LEFT JOIN PUNTENBLADCATEGORIE ON (
(BM_CATEGORIE_FK = PLC_ID)
OR (BB_CATEGORIE_FK = PLC_ID)
)
LEFT JOIN (
SELECT
PLC_ID AS PLCEV_CATEGORIE_FK,
EV_TYPE AS PLCEV_TYPE
FROM
PUNTENBLADCATEGORIE
LEFT JOIN PUNTENBLADEVALUATIEWEGING ON (PLC_EVALUATIEWEGING_FK = PLW_ID)
LEFT JOIN EVALUATIEVERWIJZING ON (
PLW_EVALUATIEVERWIJZING_FK = EV_ID
)
) AS CATEGORIEEVALUATIE ON (PLC_ID = PLCEV_CATEGORIE_FK)
LEFT JOIN QUOTATIELIJST ON (
(VB_QUOTATIELIJST_FK = QL_ID)
OR (BM_QUOTATIELIJST_FK = QL_ID)
)
LEFT JOIN QUOTATIELIJSTELEMENT ON (BW_LIJSTELEMENT_FK = QLE_ID)
LEFT JOIN EVALUATIEVERWIJZING ON (
BEOORDELINGEN.EV_ID = EVALUATIEVERWIJZING.EV_ID
)
LEFT JOIN INGVAK ON (PL_INGVAK_FK = IV_ID)
LEFT JOIN DAGELIJKSWERK ON (EV_DAGELIJKSWERK_FK = DR_ID)
LEFT JOIN EXAMEN ON (EV_EXAMEN_FK = EX_ID)
LEFT JOIN PERIODEEVALUATIE ON (
(EV_PERIODEEVALUATIE_FK = PEV_ID)
OR (DR_PERIODEEVALUATIE_FK = PEV_ID)
OR (EX_PERIODEEVALUATIE_FK = PEV_ID)
)
LEFT JOIN JAAREVALUATIE ON (EV_JAAREVALUATIE_FK = JE_ID)
WHERE
(
BEOORDELINGEN.EV_ID IN (
112, 101, 114, 100, 111, 138, 139, 136,
141, 135, 137, 127, 128, 125, 130, 131,
124, 126, 104, 106, 96, 107, 108, 95,
99
)
)
AND (
PL_ID IN (
781, 815, 722, 728, 806, 705, 741, 808,
731, 753, 841, 821, 845, 777, 813, 816,
723, 858, 771, 805, 837, 807, 730, 755,
840, 822, 846, 778, 820, 817, 724, 859,
727, 793, 742, 734, 732, 754, 842, 823,
848, 779, 814, 818, 739, 747, 773, 792,
745, 735, 733, 756, 844, 824, 847, 811,
812, 819, 738, 860, 713, 764, 744, 736,
718, 863, 843, 825, 850, 810, 791, 785,
740, 748, 772, 765, 838, 749, 719, 861,
706, 826, 851, 721, 790, 786, 737, 803,
726, 766, 839, 795, 770, 862, 707, 827,
849, 801, 782, 787, 833, 855, 762, 715,
758, 794, 767, 864, 708, 831, 852, 802
)
)
ORDER BY
PL_ID

Invalid identifier error when using RIGHT JOIN inside FROM clause

I want to use within a FROM a subset of 2 tables using RIGHT JOIN (I want from that subset all the rows of ITV2_VEHICULOS whose ID is not in ITV2_HIST_VEHICULOS) so that the SELECT "takes" the data from there and with the WHERE it can filter
My query:
SELECT
*
FROM
ITV2_INSPECCIONES I,
ITV2_HORAS_INSPECCION HI_FIN,
ITV2_INSPECCIONES I_SIG,
ITV2_HORAS_INSPECCION HI_SIG_INI,
ITV2_HIST_VEHICULOS VH,
ITV2_CATEGORIAS_VEHICULO CAT,
ITV2_CLASIF_VEH_CONS CVC,
ITV2_CLASIF_VEH_USO CVU,
(
SELECT
*
FROM
ITV2_HIST_VEHICULOS VH
RIGHT JOIN ITV2_VEHICULOS V ON
VH.C_VEHICULO_ID = V.C_VEHICULO_ID
) VI
WHERE
I.C_TIPO_INSPECCION = 1
AND I.F_DESFAVORABLE IS NOT NULL
AND I.C_RESULTADO IN(
3,
4
)
AND I.C_VEHICULO_ID = VI.C_VEHICULO_ID
AND VI.C_CATEGORIA_ID = CAT.C_CATEGORIA_ID
AND VI.C_CLASIF_VEH_CONS_ID = CVC.C_CLASIF_VEH_CONS_ID
AND VI.C_CLASIF_VEH_USO_ID = CVU.C_CLASIF_VEH_USO_ID -- HORAS
AND I.C_ESTACION_ID = HI_FIN.C_ESTACION_ID
AND I.C_INSPECCION_ID = HI_FIN.C_INSPECCION_ID
AND I.N_ANNO = HI_FIN.N_ANNO
AND HI_FIN.C_TIPO_HORA_ID = 6 -- INSPECCION SIGUIENTE
AND I.C_ESTACION_ID = I_SIG.C_ESTACION_ID_FASE_ANT
AND I.C_INSPECCION_ID = I_SIG.C_INSPECCION_ID_FASE_ANT
AND I.N_ANNO = I_SIG.N_ANNO_FASE_ANT --
AND I_SIG.N_ANNO IN(
2013,
2014,
2015,
2016,
2017,
2018
)
AND I_SIG.C_ESTACION_ID IN(
3,
21,
22,
26,
28,
32,
34,
37,
41,
47,
53,
59,
60
)
AND I_SIG.F_INSPECCION >= '01/09/2015'
AND I_SIG.F_INSPECCION <= '30/09/2018' --
AND I_SIG.F_DESFAVORABLE IS NULL
AND I_SIG.C_RESULTADO IN(
1,
2
) -- Y HORAS
AND I_SIG.C_ESTACION_ID = HI_SIG_INI.C_ESTACION_ID
AND I_SIG.C_INSPECCION_ID = HI_SIG_INI.C_INSPECCION_ID
AND I_SIG.N_ANNO = HI_SIG_INI.N_ANNO
AND HI_SIG_INI.C_TIPO_HORA_ID = 1
--GROUP BY...
I expect in the output:
C_ESTACION_ID(FROM I) |C_VEHICULO_ID(FROM(I) |C_TIPO_HORA_ID(FROM HI_FIN)|F_HORA (FROM I_FIN) |A_MATRICULA FROM (V) | F_CAMBIO FROM (VH -> IF subdata of V EXISTS)
---------------------|----------------------|---------------------------|--------------------|---------------------|---------------------------------------
This is what your query would look like if you use "explicit join syntax" instead of just some commas between table names:
SELECT *
FROM ITV2_INSPECCIONES I
INNER JOIN ITV2_HORAS_INSPECCION HI_FIN ON I.C_ESTACION_ID = HI_FIN.C_ESTACION_ID
AND I.C_INSPECCION_ID = HI_FIN.C_INSPECCION_ID
AND I.N_ANNO = HI_FIN.N_ANNO
INNER JOIN ITV2_INSPECCIONES I_SIG ON I.C_ESTACION_ID = I_SIG.C_ESTACION_ID_FASE_ANT
AND I.C_INSPECCION_ID = I_SIG.C_INSPECCION_ID_FASE_ANT
AND I.N_ANNO = I_SIG.N_ANNO_FASE_ANT
INNER JOIN ITV2_HORAS_INSPECCION HI_SIG_INI ON I_SIG.C_ESTACION_ID = HI_SIG_INI.C_ESTACION_ID
AND I_SIG.C_INSPECCION_ID = HI_SIG_INI.C_INSPECCION_ID
AND I_SIG.N_ANNO = HI_SIG_INI.N_ANNO
WHERE I.C_TIPO_INSPECCION = 1
AND I.F_DESFAVORABLE IS NOT NULL
AND I.C_RESULTADO IN (3, 4)
AND HI_FIN.C_TIPO_HORA_ID = 6 -- INSPECCION SIGUIENTE
AND HI_SIG_INI.C_TIPO_HORA_ID = 1
AND I_SIG.F_INSPECCION >= '01/09/2015'
AND I_SIG.F_INSPECCION <= '30/09/2018'
AND I_SIG.F_DESFAVORABLE IS NULL
AND I_SIG.N_ANNO IN (2013, 2014, 2015, 2016, 2017, 2018)
AND I_SIG.C_ESTACION_ID IN (3, 21, 22, 26, 28, 32, 34, 37, 41, 47, 53, 59, 60)
AND I_SIG.C_RESULTADO IN (1, 2) -- Y HORAS
Now I had to pull out several tables and the subquery from that because, frankly, they don't make much sense to me:
ITV2_HIST_VEHICULOS VH, << no join conditions to preceding tables
ITV2_CATEGORIAS_VEHICULO CAT, << no join conditions to preceding tables
ITV2_CLASIF_VEH_CONS CVC, << no join conditions to preceding tables
ITV2_CLASIF_VEH_USO CVU, << no join conditions to preceding tables
(
SELECT
*
FROM ITV2_VEHICULOS V
LEFT JOIN ITV2_HIST_VEHICULOS VH ON
VH.C_VEHICULO_ID = V.C_VEHICULO_ID
) VI
AND I.C_VEHICULO_ID = VI.C_VEHICULO_ID
AND VI.C_CATEGORIA_ID = CAT.C_CATEGORIA_ID
AND VI.C_CLASIF_VEH_CONS_ID = CVC.C_CLASIF_VEH_CONS_ID
AND VI.C_CLASIF_VEH_USO_ID = CVU.C_CLASIF_VEH_USO_ID

How do you only return one field when there are multiple entries for each field?

I am trying to only return one email address for each employee. An Employee can be both an employee and a student. If you have both an employee and student email address then I only want to return the employee email address else if you only have student email address then return the student email address.
Here is the entire query:
select --spriden_pidm as pidm,
spriden_id as ban_id,
spriden_last_name as lastname,
spriden_first_name as firstname,
gmal.email,
phone_number.area || phone_number.phone as phone_number,
addr.permanent_address AS street,
addr.permanent_city AS city,
addr.permanent_state AS state,
addr.permanent_zip AS zip,
case
when nbrjobs_ecls_code in ('E1', 'E2', 'EN', 'F1', 'F2') and nbrjobs_ann_salary between 0 and 49999.99 then 'EHRA1'
when nbrjobs_ecls_code in ('E1', 'E2', 'EN', 'F1', 'F2') and nbrjobs_ann_salary between 50000 and 99999.99 then 'EHRA2'
when nbrjobs_ecls_code in ('E1', 'E2', 'EN', 'F1', 'F2') and nbrjobs_ann_salary between 100000 and 149999.99 then 'EHRA3'
when nbrjobs_ecls_code in ('E1', 'E2', 'EN', 'F1', 'F2') and nbrjobs_ann_salary >= 150000 then 'EHRA4'
when nbrjobs_ecls_code in ('SE', 'SN', 'LE') and nbrjobs_ann_salary between 0 and 49999.99 then 'SHRA1'
when nbrjobs_ecls_code in ('SE', 'SN', 'LE') and nbrjobs_ann_salary between 50000 and 99999.99 then 'SHRA2'
when nbrjobs_ecls_code in ('SE', 'SN', 'LE') and nbrjobs_ann_salary between 100000 and 149999.99 then 'SHRA3'
when nbrjobs_ecls_code in ('SE', 'SN', 'LE') and nbrjobs_ann_salary >= 150000 then 'SHRA4'
when nbrjobs_ecls_code in ('FA') then 'AF'
when nbrjobs_ecls_code in ('SH', 'SS', 'TS', 'WS') then 'M1'
else
null
end as empl_cat
from nbrjobs a,
spriden,
(select goremal_pidm as pidm,
goremal_email_address as email
from goremal
where goremal_emal_code in ('EMPL', 'STDN')
and goremal_status_ind = 'A') gmal,
(SELECT sprtele_pidm AS pidm,
sprtele_phone_area AS area,
sprtele_phone_number AS phone
FROM sprtele c
WHERE sprtele_tele_code = 'CA'
AND sprtele_primary_ind = 'Y'
AND sprtele_status_ind IS NULL
AND sprtele_seqno =
(SELECT MAX (sprtele_seqno)
FROM sprtele
WHERE sprtele_tele_code = 'CA'
AND sprtele_primary_ind = 'Y'
AND sprtele_status_ind IS NULL
AND sprtele_pidm = c.sprtele_pidm)) phone_number,
--spraddr
(SELECT spraddr_pidm AS pidm,
spraddr_street_line1 AS permanent_address,
spraddr_city AS permanent_city,
spraddr_stat_code AS permanent_state,
spraddr_zip AS permanent_zip
FROM spraddr b
WHERE spraddr_atyp_code = 'CA'
AND spraddr_status_ind IS NULL
AND spraddr_seqno =
(SELECT MAX (spraddr_seqno)
FROM spraddr
WHERE spraddr_atyp_code = 'CA'
AND spraddr_status_ind IS NULL
AND spraddr_pidm = b.spraddr_pidm)) addr
where a.nbrjobs_pidm = spriden_pidm
and a.nbrjobs_pidm = gmal.pidm(+)
and a.nbrjobs_pidm = phone_number.pidm(+)
and a.nbrjobs_pidm = addr.pidm(+)
and spriden_change_ind is null
and a.nbrjobs_sgrp_code = to_char(sysdate, 'YYYY')
and a.nbrjobs_effective_date = (select max(b.nbrjobs_effective_date)
from nbrjobs b
where b.nbrjobs_pidm = a.nbrjobs_pidm
and b.nbrjobs_posn = a.nbrjobs_posn
and b.nbrjobs_effective_date <= sysdate
--and b.nbrjobs_ecls_code in ('E1','E2','EN','F1','F2','SE','SN','LE')
and b.nbrjobs_ecls_code in ('E1','E2','EN','F1','F2','SE','SN','LE', 'RF', 'AF', 'FA', 'SH', 'SS', 'TS', 'WS')
and b.nbrjobs_sgrp_code = to_char(sysdate, 'YYYY'))
and a.nbrjobs_status <> 'T';`
and this is the part of the query I am trying to change to return the desired email address
(select goremal_pidm as pidm,
goremal_email_address as email
from goremal
where goremal_emal_code in ('EMPL', 'STDN')
and goremal_status_ind = 'A') gmal,
So the issue is that the query will return two email addresses if the employee is also a student? What you can do in this case is PIVOT the data, then use COALESCE() to get the student email where the employee email is NULL. The below query would replace the problematic subquery:
SELECT pidm, COALESCE(empl_email, stdn_email) AS email
FROM (
SELECT goremal_pidm AS pidm, goremal_email_address AS email, goremal_emal_code
FROM goremal
WHERE goremal_emal_code in ('EMPL', 'STDN')
AND goremal_status_ind = 'A'
) PIVOT (
MAX(email) FOR goremal_emal_code IN ('EMPL' AS empl_email, 'STDN' AS stdn_email)
)
EDIT: As an aside, you can use conditional aggregation instead of an explicit PIVOT (helpful if you're using Oracle 9i or lower):
SELECT pidm, COALESCE(empl_email, stdn_email) AS email FROM (
SELECT goremal_pidm AS pidm
, MAX(CASE WHEN goremal_emal_code = 'EMPL' THEN goremal_email_address END) AS empl_email
, MAX(CASE WHEN goremal_emal_code = 'STDN' THEN goremal_email_address END) AS stdn_email
FROM goremal
WHERE goremal_emal_code in ('EMPL', 'STDN')
AND goremal_status_ind = 'A'
GROUP BY goremal_pidm
)
Hope this helps.
Try using NVL2, as a example for your case -
NVL2(EMP_EMAIL_ADR, EMP_EMAIL_ADR, STDN_EMAIL_ADR)
This clause will return if the Employee email address is not null else it returns Student email address.
Hope this helps.

Access 2016 Using Top in a Union Query

I am trying to create a query that will output the top 6 results based on a union of two other queries. The two queries are as follows:
SELECT GameData.GameID,
GameData.DivisionID,
GameData.SeasonID,
GameData.HomeTeamID AS TeamID,
GameData.GameDate,
IIf([FullTimeResult] = 'H', 1, 0) AS W,
IIf([FullTimeResult] = 'D', 1, 0) AS D,
IIf([FullTimeResult] = 'A', 1, 0) AS L,
IIf([HalfTimeResult] = 'H', 1, 0) AS WHT,
IIf([HalfTimeResult] = 'D', 1, 0) AS DHT,
IIf([HalfTimeResult] = 'A', 1, 0) AS LHT,
GameData.FullTimeHomeGoals AS GS,
GameData.FullTimeAwayGoals AS GC,
IIf([FullTimeResult] = 'H', 3, IIf([FullTimeResult] = 'D', 1, 0)) AS P,
GameData.HalfTimeHomeGoals AS GSHT,
GameData.HalfTimeAwayGoals AS GCHT,
GameData.HomeShots AS Sh,
GameData.AwayShots AS ShA,
GameData.HomeShotsOnTarget AS ShOnT,
GameData.AwayShotsOnTarget AS ShAOnT,
GameData.HomeFouls AS FM,
GameData.AwayFouls AS FA,
GameData.HomeCorners AS C,
GameData.AwayCorners AS CA,
GameData.HomeYellowCards AS YC,
GameData.AwayYellowCards AS YCA,
GameData.HomeRedCards AS RC,
GameData.AwayRedCards AS RCA
FROM TeamsDivSea
INNER JOIN GameData ON TeamsDivSea.TeamID = GameData.HomeTeamID
WHERE (
(
(GameData.GameID) IN (
SELECT TOP 3 GameID
FROM GameData AS Dupe
WHERE Dupe.HomeTeamID = GameData.HomeTeamID
ORDER BY Dupe.GameDate DESC,
Dupe.GameID DESC
)
)
);
SELECT GameData.GameID,
GameData.DivisionID,
GameData.SeasonID,
GameData.AwayTeamID AS TeamID,
GameData.GameDate,
IIf([FullTimeResult] = 'A', 1, 0) AS W,
IIf([FullTimeResult] = 'D', 1, 0) AS D,
IIf([FullTimeResult] = 'H', 1, 0) AS L,
IIf([HalfTimeResult] = 'A', 1, 0) AS WHT,
IIf([HalfTimeResult] = 'D', 1, 0) AS DHT,
IIf([HalfTimeResult] = 'H', 1, 0) AS LHT,
GameData.FullTimeAwayGoals AS GS,
GameData.FullTimeHomeGoals AS GC,
IIf([FullTimeResult] = 'A', 3, IIf([FullTimeResult] = 'D', 1, 0)) AS P,
GameData.HalfTimeAwayGoals AS GSHT,
GameData.HalfTimeHomeGoals AS GCHT,
GameData.AwayShots AS Sh,
GameData.HomeShots AS ShA,
GameData.AwayShotsOnTarget AS ShOnT,
GameData.HomeShotsOnTarget AS ShAOnT,
GameData.AwayFouls AS FM,
GameData.HomeFouls AS FA,
GameData.AwayCorners AS C,
GameData.HomeCorners AS CA,
GameData.AwayYellowCards AS YC,
GameData.HomeYellowCards AS YCA,
GameData.AwayRedCards AS RC,
GameData.HomeRedCards AS RCA
FROM TeamsDivSea
INNER JOIN GameData ON TeamsDivSea.TeamID = GameData.AwayTeamID
WHERE (
(
(GameData.GameID) IN (
SELECT TOP 3 GameID
FROM GameData AS Dupe
WHERE Dupe.AwayTeamID = GameData.AwayTeamID
ORDER BY Dupe.GameDate DESC,
Dupe.GameID DESC
)
)
);
Is it possible to create a union query only using one SELECT TOP statement so only the top 6 are output from the joined results?
Many thanks
This should work - basically UNION your two queries and select the top 6.
SELECT TOP 6 GameID, DivisionID, SeasonID, TeamID, GameDate, W,D,L,WHT,DHT,LHT,GS,GC,P,GSHT,GCHT,Sh,shA, shOnT, ShAOnt, FM,FA,C,CA,YC,YCA,RC,RCA
FROM (
SELECT GameData.GameID,
GameData.DivisionID,
GameData.SeasonID,
GameData.HomeTeamID AS TeamID,
GameData.GameDate,
IIf([FullTimeResult] = 'H', 1, 0) AS W,
IIf([FullTimeResult] = 'D', 1, 0) AS D,
IIf([FullTimeResult] = 'A', 1, 0) AS L,
IIf([HalfTimeResult] = 'H', 1, 0) AS WHT,
IIf([HalfTimeResult] = 'D', 1, 0) AS DHT,
IIf([HalfTimeResult] = 'A', 1, 0) AS LHT,
GameData.FullTimeHomeGoals AS GS,
GameData.FullTimeAwayGoals AS GC,
IIf([FullTimeResult] = 'H', 3, IIf([FullTimeResult] = 'D', 1, 0)) AS P,
GameData.HalfTimeHomeGoals AS GSHT,
GameData.HalfTimeAwayGoals AS GCHT,
GameData.HomeShots AS Sh,
GameData.AwayShots AS ShA,
GameData.HomeShotsOnTarget AS ShOnT,
GameData.AwayShotsOnTarget AS ShAOnT,
GameData.HomeFouls AS FM,
GameData.AwayFouls AS FA,
GameData.HomeCorners AS C,
GameData.AwayCorners AS CA,
GameData.HomeYellowCards AS YC,
GameData.AwayYellowCards AS YCA,
GameData.HomeRedCards AS RC,
GameData.AwayRedCards AS RCA
FROM TeamsDivSea
INNER JOIN GameData ON TeamsDivSea.TeamID = GameData.HomeTeamID
WHERE (
(
(GameData.GameID) IN (
SELECT TOP 3 GameID
FROM GameData AS Dupe
WHERE Dupe.HomeTeamID = GameData.HomeTeamID
ORDER BY Dupe.GameDate DESC,
Dupe.GameID DESC
)
)
)
UNION ALL SELECT GameData.GameID,
GameData.DivisionID,
GameData.SeasonID,
GameData.AwayTeamID AS TeamID,
GameData.GameDate,
IIf([FullTimeResult] = 'A', 1, 0),
IIf([FullTimeResult] = 'D', 1, 0),
IIf([FullTimeResult] = 'H', 1, 0),
IIf([HalfTimeResult] = 'A', 1, 0),
IIf([HalfTimeResult] = 'D', 1, 0),
IIf([HalfTimeResult] = 'H', 1, 0),
GameData.FullTimeAwayGoals,
GameData.FullTimeHomeGoals,
IIf([FullTimeResult] = 'A', 3, IIf([FullTimeResult] = 'D', 1, 0)),
GameData.HalfTimeAwayGoals,
GameData.HalfTimeHomeGoals,
GameData.AwayShots,
GameData.HomeShots,
GameData.AwayShotsOnTarget,
GameData.HomeShotsOnTarget,
GameData.AwayFouls,
GameData.HomeFouls,
GameData.AwayCorners,
GameData.HomeCorners,
GameData.AwayYellowCards,
GameData.HomeYellowCards,
GameData.AwayRedCards,
GameData.HomeRedCards
FROM TeamsDivSea
INNER JOIN GameData ON TeamsDivSea.TeamID = GameData.AwayTeamID
WHERE (
(
(GameData.GameID) IN (
SELECT TOP 3 GameID
FROM GameData AS Dupe
WHERE Dupe.AwayTeamID = GameData.AwayTeamID
ORDER BY Dupe.GameDate DESC,
Dupe.GameID DESC
)
)
)
)

SQL Server Fuzzy Search with Percentage of match

I am using SQL Server 2008 R2 SP1.
I have a table with about 36034 records of customers.
I am trying to implement Fuzy search on Customer Name field.
Here is Function for Fuzzy Search
ALTER FUNCTION [Party].[FuzySearch]
(
#Reference VARCHAR(200) ,
#Target VARCHAR(200)
)
RETURNS DECIMAL(5, 2)
WITH SCHEMABINDING
AS
BEGIN
DECLARE #score DECIMAL(5, 2)
SELECT #score = CASE WHEN #Reference = #Target
THEN CAST(100 AS NUMERIC(5, 2))
WHEN #Reference IS NULL
OR #Target IS NULL
THEN CAST(0 AS NUMERIC(5, 2))
ELSE ( SELECT [Score %] = CAST(SUM(LetterScore)
* 100.0 / MAX(WordLength
* WordLength) AS NUMERIC(5,
2))
FROM ( -- do
SELECT seq = t1.n ,
ref.Letter ,
v.WordLength ,
LetterScore = v.WordLength
- ISNULL(MIN(tgt.n),
v.WordLength)
FROM ( -- v
SELECT
Reference = LEFT(#Reference
+ REPLICATE('_',
WordLength),
WordLength) ,
Target = LEFT(#Target
+ REPLICATE('_',
WordLength),
WordLength) ,
WordLength = WordLength
FROM
( -- di
SELECT
WordLength = MAX(WordLength)
FROM
( VALUES
( DATALENGTH(#Reference)),
( DATALENGTH(#Target)) ) d ( WordLength )
) di
) v
CROSS APPLY ( -- t1
SELECT TOP ( WordLength )
n
FROM
( VALUES ( 1),
( 2), ( 3), ( 4),
( 5), ( 6), ( 7),
( 8), ( 9),
( 10), ( 11),
( 12), ( 13),
( 14), ( 15),
( 16), ( 17),
( 18), ( 19),
( 20), ( 21),
( 22), ( 23),
( 24), ( 25),
( 26), ( 27),
( 28), ( 29),
( 30), ( 31),
( 32), ( 33),
( 34), ( 35),
( 36), ( 37),
( 38), ( 39),
( 40), ( 41),
( 42), ( 43),
( 44), ( 45),
( 46), ( 47),
( 48), ( 49),
( 50), ( 51),
( 52), ( 53),
( 54), ( 55),
( 56), ( 57),
( 58), ( 59),
( 60), ( 61),
( 62), ( 63),
( 64), ( 65),
( 66), ( 67),
( 68), ( 69),
( 70), ( 71),
( 72), ( 73),
( 74), ( 75),
( 76), ( 77),
( 78), ( 79),
( 80), ( 81),
( 82), ( 83),
( 84), ( 85),
( 86), ( 87),
( 88), ( 89),
( 90), ( 91),
( 92), ( 93),
( 94), ( 95),
( 96), ( 97),
( 98), ( 99),
( 100), ( 101),
( 102), ( 103),
( 104), ( 105),
( 106), ( 107),
( 108), ( 109),
( 110), ( 111),
( 112), ( 113),
( 114), ( 115),
( 116), ( 117),
( 118), ( 119),
( 120), ( 121),
( 122), ( 123),
( 124), ( 125),
( 126), ( 127),
( 128), ( 129),
( 130), ( 131),
( 132), ( 133),
( 134), ( 135),
( 136), ( 137),
( 138), ( 139),
( 140), ( 141),
( 142), ( 143),
( 144), ( 145),
( 146), ( 147),
( 148), ( 149),
( 150), ( 151),
( 152), ( 153),
( 154), ( 155),
( 156), ( 157),
( 158), ( 159),
( 160), ( 161),
( 162), ( 163),
( 164), ( 165),
( 166), ( 167),
( 168), ( 169),
( 170), ( 171),
( 172), ( 173),
( 174), ( 175),
( 176), ( 177),
( 178), ( 179),
( 180), ( 181),
( 182), ( 183),
( 184), ( 185),
( 186), ( 187),
( 188), ( 189),
( 190), ( 191),
( 192), ( 193),
( 194), ( 195),
( 196), ( 197),
( 198), ( 199),
( 200)
) t2 ( n )
) t1
CROSS APPLY ( SELECT
Letter = SUBSTRING(Reference,
t1.n, 1)
) ref
OUTER APPLY ( -- tgt
SELECT TOP ( WordLength )
n = ABS(t1.n
- t2.n)
FROM
( VALUES ( 1),
( 2), ( 3), ( 4),
( 5), ( 6), ( 7),
( 8), ( 9),
( 10), ( 11),
( 12), ( 13),
( 14), ( 15),
( 16), ( 17),
( 18), ( 19),
( 20), ( 21),
( 22), ( 23),
( 24), ( 25),
( 26), ( 27),
( 28), ( 29),
( 30), ( 31),
( 32), ( 33),
( 34), ( 35),
( 36), ( 37),
( 38), ( 39),
( 40), ( 41),
( 42), ( 43),
( 44), ( 45),
( 46), ( 47),
( 48), ( 49),
( 50), ( 51),
( 52), ( 53),
( 54), ( 55),
( 56), ( 57),
( 58), ( 59),
( 60), ( 61),
( 62), ( 63),
( 64), ( 65),
( 66), ( 67),
( 68), ( 69),
( 70), ( 71),
( 72), ( 73),
( 74), ( 75),
( 76), ( 77),
( 78), ( 79),
( 80), ( 81),
( 82), ( 83),
( 84), ( 85),
( 86), ( 87),
( 88), ( 89),
( 90), ( 91),
( 92), ( 93),
( 94), ( 95),
( 96), ( 97),
( 98), ( 99),
( 100), ( 101),
( 102), ( 103),
( 104), ( 105),
( 106), ( 107),
( 108), ( 109),
( 110), ( 111),
( 112), ( 113),
( 114), ( 115),
( 116), ( 117),
( 118), ( 119),
( 120), ( 121),
( 122), ( 123),
( 124), ( 125),
( 126), ( 127),
( 128), ( 129),
( 130), ( 131),
( 132), ( 133),
( 134), ( 135),
( 136), ( 137),
( 138), ( 139),
( 140), ( 141),
( 142), ( 143),
( 144), ( 145),
( 146), ( 147),
( 148), ( 149),
( 150), ( 151),
( 152), ( 153),
( 154), ( 155),
( 156), ( 157),
( 158), ( 159),
( 160), ( 161),
( 162), ( 163),
( 164), ( 165),
( 166), ( 167),
( 168), ( 169),
( 170), ( 171),
( 172), ( 173),
( 174), ( 175),
( 176), ( 177),
( 178), ( 179),
( 180), ( 181),
( 182), ( 183),
( 184), ( 185),
( 186), ( 187),
( 188), ( 189),
( 190), ( 191),
( 192), ( 193),
( 194), ( 195),
( 196), ( 197),
( 198), ( 199),
( 200) ) t2 ( n )
WHERE
SUBSTRING(#Target,
t2.n, 1) = ref.Letter
) tgt
GROUP BY t1.n ,
ref.Letter ,
v.WordLength
) do
)
END
RETURN #score
END
Here is the query to call the function
select [Party].[FuzySearch]('First Name Middle Name Last Name', C.FirstName) from dbo.Customer C
This is taking about 2 minutes 22 seconds to give me the percentage of fuzzy match for all
How can I fix this to run in lessthan a second. Any suggestions on my function to make it more robust.
Expected ouput is 45.34, 40.00, 100.00, 23.00, 81.23.....
The best I have been able to do is simplify some of the query, and change it to a table valued function. Scalar functions are notoriously poor performers, and the benefit of an inline TVF is that the query definition is expanded out into the main query, much like a view.
This reduces the execution time significantly on the tests I have done.
ALTER FUNCTION dbo.FuzySearchTVF (#Reference VARCHAR(200), #Target VARCHAR(200))
RETURNS TABLE
AS
RETURN
( WITH N (n) AS
( SELECT TOP (ISNULL(CASE WHEN DATALENGTH(#Reference) > DATALENGTH(#Target)
THEN DATALENGTH(#Reference)
ELSE DATALENGTH(#Target)
END, 0))
ROW_NUMBER() OVER(ORDER BY n1.n)
FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) AS N1 (n)
CROSS JOIN (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) AS N2 (n)
CROSS JOIN (VALUES (1), (1)) AS N3 (n)
WHERE #Reference IS NOT NULL AND #Target IS NOT NULL
), Src AS
( SELECT Reference = CASE WHEN DATALENGTH(#Reference) > DATALENGTH(#Target) THEN #Reference
ELSE #Reference + REPLICATE('_', DATALENGTH(#Target) - DATALENGTH(#Reference))
END,
Target = CASE WHEN DATALENGTH(#Target) > DATALENGTH(#Reference) THEN #Target
ELSE #Target + REPLICATE('_', DATALENGTH(#Target) - DATALENGTH(#Reference))
END,
WordLength = CASE WHEN DATALENGTH(#Reference) > DATALENGTH(#Target) THEN DATALENGTH(#Reference) ELSE DATALENGTH(#Target) END
WHERE #Reference IS NOT NULL
AND #Target IS NOT NULL
AND #Reference != #Target
), Scores AS
( SELECT seq = t1.n ,
Letter = SUBSTRING(s.Reference, t1.n, 1),
s.WordLength ,
LetterScore = s.WordLength - ISNULL(MIN(ABS(t1.n - t2.n)), s.WordLength)
FROM Src AS s
CROSS JOIN N AS t1
INNER JOIN N AS t2
ON SUBSTRING(#Target, t2.n, 1) = SUBSTRING(s.Reference, t1.n, 1)
WHERE #Reference IS NOT NULL
AND #Target IS NOT NULL
AND #Reference != #Target
GROUP BY t1.n, SUBSTRING(s.Reference, t1.n, 1), s.WordLength
)
SELECT [Score] = 100
WHERE #Reference = #Target
UNION ALL
SELECT 0
WHERE #Reference IS NULL OR #Target IS NULL
UNION ALL
SELECT CAST(SUM(LetterScore) * 100.0 / MAX(WordLength * WordLength) AS NUMERIC(5, 2))
FROM Scores
WHERE #Reference IS NOT NULL
AND #Target IS NOT NULL
AND #Reference != #Target
GROUP BY WordLength
);
And this would be called as:
SELECT f.Score
FROM dbo.Customer AS c
CROSS APPLY [dbo].[FuzySearch]('First Name Middle Name Last Name', c.FirstName) AS f
It is still a fairly complex function though, and, depending on the number of records in your customer table, I think getting it down to 1 second is going to be a bit of a challenge.
This is how I could accomplish this:
Explained further # SQL Server Fuzzy Search - Levenshtein Algorithm
Create below file using any editor of your choice:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class StoredFunctions
{
[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = false)]
public static SqlDouble Levenshtein(SqlString stringOne, SqlString stringTwo)
{
#region Handle for Null value
if (stringOne.IsNull)
stringOne = new SqlString("");
if (stringTwo.IsNull)
stringTwo = new SqlString("");
#endregion
#region Convert to Uppercase
string strOneUppercase = stringOne.Value.ToUpper();
string strTwoUppercase = stringTwo.Value.ToUpper();
#endregion
#region Quick Check and quick match score
int strOneLength = strOneUppercase.Length;
int strTwoLength = strTwoUppercase.Length;
int[,] dimention = new int[strOneLength + 1, strTwoLength + 1];
int matchCost = 0;
if (strOneLength + strTwoLength == 0)
{
return 100;
}
else if (strOneLength == 0)
{
return 0;
}
else if (strTwoLength == 0)
{
return 0;
}
#endregion
#region Levenshtein Formula
for (int i = 0; i <= strOneLength; i++)
dimention[i, 0] = i;
for (int j = 0; j <= strTwoLength; j++)
dimention[0, j] = j;
for (int i = 1; i <= strOneLength; i++)
{
for (int j = 1; j <= strTwoLength; j++)
{
if (strOneUppercase[i - 1] == strTwoUppercase[j - 1])
matchCost = 0;
else
matchCost = 1;
dimention[i, j] = System.Math.Min(System.Math.Min(dimention[i - 1, j] + 1, dimention[i, j - 1] + 1), dimention[i - 1, j - 1] + matchCost);
}
}
#endregion
// Calculate Percentage of match
double percentage = System.Math.Round((1.0 - ((double)dimention[strOneLength, strTwoLength] / (double)System.Math.Max(strOneLength, strTwoLength))) * 100.0, 2);
return percentage;
}
};
Name it levenshtein.cs
Go to Command Prompt. Go to the file directory of levenshtein.cs then call csc.exe /t: library /out: UserFunctions.dll levenshtein.cs you may have to give the full path of csc.exe from NETFrameWork 2.0.
Once your DLL is ready. Add it to the assemblies Database>>Programmability>>Assemblies>> New Assembly.
Create function in your database:
CREATE FUNCTION dbo.LevenshteinSVF
(
#S1 NVARCHAR(200) ,
#S2 NVARCHAR(200)
)
RETURNS FLOAT
AS EXTERNAL NAME
UserFunctions.StoredFunctions.Levenshtein
GO
In my case I had to enable clr:
sp_configure 'clr enabled', 1
GO
reconfigure
GO
Test the function:
SELECT dbo.LevenshteinSVF('James','James Bond')
Result: 50 % match