SQL Query merge - sql

I am working on a scenario where for example I need to search customers by telephone and/or email address.
for example
if :lv_telephone <> '' then
lt_phone = select a.customer from customer_master a inner join telephone as b on a.address = b.address;
end if;
if :lv_email <> '' then
lt_email = select a.customer from customer_master a inner join email as b on a.address = b.address;
end if;
DB - HANA.
I want to create one final result merging both email and phone table only if they both have result set. Any pointers on how to do it?

You may avoid any script logic and "merge" your results in a plain SQL with conditions on variables (regardless of their source):
select a.customer
from customer_master a
left join telephone t
on a.address = t.address
and lv_telephone != ''
left join email e
on a.address = e.address
and lv_email != ''
where 1 = 1
/*Applies only when lv_telephone is not ''*/
and map(lv_telephone, '', '', t.address) is not null
/*Applies only when lv_email is not ''*/
and map(lv_email, '', '', e.address) is not null
This may also be adapted if you need to filter by passed values: compare with variable value instead of null. If variables come from SQLScript code, this can be embedded into SQLScript code. If they come from outside (e.g. some external language communicating with your DB), you may use bind variables and plain SQL withour additional script wrapper.
Below is example with standard SAP tables:
create procedure test_sp ( in iv_tel nvarchar(10), in iv_email nvarchar(10))
as
begin
select b.*
from sapdbh.t006 as b
left join sapdbh.t006a as t
on b.msehi = t.msehi
and t.spras = 'R'
and :iv_tel != ''
left join sapdbh.t006t as e
on b.dimid = e.dimid
and e.spras = 'R'
and :iv_email != ''
where 1 = 1
and case
when :iv_tel != ''
then t.msehi
else ''
end is not null
and case
when :iv_email != ''
then e.dimid
else ''
end is not null
;
end;
And execution plans below (I didn't use mandt in join so you may observe results are multiplied when join is introduced):
With call test_sp('', ''); one table accessed.
With call test_sp('X', ''); two tables accessed.
With call test_sp('X', 'X'); three tables accessed.

Related

Oracle SQL - Case statement with iteration

The ASCII table values should be compared to the s.manure_type. For each record in the following table below the QuantityText case statement should do a comparison. The value it needs to select is e.g. oats,velvet beans, other none.
select
c.id customer_num,
c.type type,
s.id_text sample_num,
c.sasa_grower_code s_grower,
c.address s_address1,
c.postalcode s_post_code,
c.email q1_email,
nvl(c.client_name, c.farm_name )s_company,
c.farm_name s_estate,
c.contact_name s_contact,
s.id_numeric id_numeric,
s.id_text fas_lab_id,
s.date_received received_date,
s.date_printed printed_date,
s.sampled_date sampled_date,
e.name S_AREA_DESCRIP,
a.name s_advisor_name,
a.email s_advisor_email,
s.order_no s_order_num,
s.field_name s_field,
p.phrase_text || ' cm' sample_depth,
cr.crop_name s_crop,
s.attyield s_yield,
s.variety s_varty,
case when s.flg_trashed is null then
'None'
else (case when s.flg_trashed = constant_pkg.get_true then
'Yes'
else (case when s.flg_trashed = constant_pkg.get_false then
'No'
else ' '
end)
end) end trashed,
case when s.flg_irrigated is null then
'None'
else (case when s.flg_irrigated = constant_pkg.get_true then
'Yes'
else (case when s.flg_irrigated = constant_pkg.get_false then
'No'
else ' '
end)
end) end s_irrig,
CASE
WHEN trim(s.manure_type) in (select p.phrase_id from phrase p where p.phrase_type = 'AL_G_MANUR') then (select p.phrase_text from phrase p)
END AS QuantityText,
'' S_GM_YIELD,
s.project_code project_code,
s.trial_ref trial_ref,
s.cost_centre cost_centre
from client c
left outer join sample s on (s.client_id = c.id)
left outer join extension e on (e.id = c.extension_id)
left outer join advisor a on (a.id = c.advisor_id)
left outer join phrase p on (p.phrase_id = s.depth)
left outer join crop cr on (cr.id = s.crop_id)
where p.phrase_type = phrase_pkg.get_soil_depth
and c.id = '211493A'
and s.fas_sample_type = sample_pkg.get_soil_sample
and s.flg_recommendation = sample_pkg.get_flg_recommendation
and s.id_numeric between 14932 and 14933
+----------------------------+
| Phrase |
+----------------------------+
|AL_G_MANUR OA Oats |
|AL_G_MANUR V Velvet Beans
|AL_G_MANUR O Other
|AL_G_MANUR N None |
+----------------------------+
But I get the error ORA-00900: Single row query returns more than one row
Missing where clause in one of the case statements is most likely the cause.
CASE
WHEN trim(s.manure_type) in
(select p.phrase_id from phrase p where p.phrase_type = 'AL_G_MANUR')
then (select p.phrase_text from phrase p) <<< NO WHERE CLAUSE ?
END AS QuantityText,
This is relatively easy to debug yourself.
Remove a single selected column
Check if error still occurs
If it does, go back to 1.
If it does not then verify why last added column errors
Problem is in the following statement
then (select p.phrase_text from phrase p)
I guess, It should be replaced with this
(select p.phrase_text from phrase p where p.phrase_type = 'AL_G_MANUR')

Condition if sql

I have this query
SELECT
SI_Num_Inventario = COALESCE (t.SI_Num_Inventario, c.SI_Num_Inventario),
SI_Ubicacion = COALESCE(t.SI_Ubicacion, c.SI_Ubicacion),
SI_Ubicacion_Fisica = COALESCE(t.SI_Ubicacion_Fisica, c.SI_Ubicacion_Fisica),
SI_Num_Articulo = COALESCE(t.SI_Articulo, c.SI_Num_Articulo),
NULL,
SI_Num_Conteo = COALESCE(cs.SI_Num_Conteo,2),
GETDATE(),
'Admin',
c.SI_OV
FROM
SI_Inventario_Teorico_QAD t
FULL JOIN
SI_Conteo c ON t.SI_Articulo = c.SI_Num_Articulo
AND t.SI_Ubicacion = c.SI_Ubicacion
INNER JOIN
SI_Maestro_Ref_QAD m ON t.SI_Articulo = m.SI_Num_Articulo
OR c.SI_Num_Articulo = m.SI_Num_Articulo
FULL JOIN
SI_Consecutivo cs ON c.SI_Num_Inventario = cs.SI_Num_Inventario
AND cs.SI_Estado = 0
WHERE
c.SI_Num_Articulo = 201423 OR t.SI_Articulo = 201423
And I'm trying to tell you that if c.SI_OV IS NULL INSERT THIS `INSERT INTO``
IF c.SI_OV IS NULL
INSERT INTO SI_Conteo(SI_Num_Inventario, SI_Ubicacion,SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,SI_Fecha_Conteo, SI_Usuario,SI_OV)
And if it is not NULL insert me this other
ELSE
INSERT INTO SI_Conteo(SI_Num_Inventario, SI_Ubicacion_Fisica, SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,SI_Fecha_Conteo, SI_Usuario,SI_OV)
END IF;
In short: the CASE construct needs to "live" in your SELECT clause of you SQL statement. The receiving INSERT clause should always mention both column names like this
INSERT INTO SI_CONTEO (SI_Num_Inventario,
SI_Ubicacion, SI_Ubicacion_fisico,
SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,
SI_Fecha_Conteo, SI_Usuario,SI_OV)
SELECT SI_Num_Inventario = COALESCE (t.SI_Num_Inventario,c.SI_Num_Inventario),
SI_Ubicacion = CASE WHEN SI_OV IS NULL THEN COALESCE(t.SI_Ubicacion, c.SI_Ubicacion) END,
SI_Ubicacion_Fisica = CASE WHEN NOT SU_OV IS NULL THEN COALESCE(t.SI_Ubicacion_Fisica, c.SI_Ubicacion_Fisica) END,
SI_Num_Articulo = COALESCE(t.SI_Articulo, c.SI_Num_Articulo),
NULL, ...
if else in non query language ~= CASE WHEN cond1 ELSE cond2 END in SQL
Use the below query:
INSERT INTO SI_Conteo(SI_Num_Inventario,SI_Ubicacion,SI_Ubicacion_Fisica,SI_Num_Articulo, SI_Cantidad,SI_Num_Conteo,SI_Fecha_Conteo,
SI_Usuario,SI_OV)
SELECT
SI_Num_Inventario = COALESCE (t.SI_Num_Inventario,c.SI_Num_Inventario),
(CASE WHEN c.SI_OV IS NULL THEN COALESCE(t.SI_Ubicacion, c.SI_Ubicacion) ELSE NULL END)AS SI_Ubicacion,
(CASE WHEN c.SI_OV IS NOT NULL THEN COALESCE(t.SI_Ubicacion_Fisica, c.SI_Ubicacion_Fisica) ELSE NULL END)AS SI_Ubicacion_Fisica,
SI_Num_Articulo = COALESCE(t.SI_Articulo, c.SI_Num_Articulo),
NULL,
SI_Num_Conteo = COALESCE(cs.SI_Num_Conteo,2),
GETDATE(),
'Admin',
c.SI_OV
FROM SI_Inventario_Teorico_QAD t
full JOIN SI_Conteo c
ON t.SI_Articulo = c.SI_Num_Articulo
AND t.SI_Ubicacion = c.SI_Ubicacion
INNER JOIN SI_Maestro_Ref_QAD m
ON t.SI_Articulo = m.SI_Num_Articulo
OR c.SI_Num_Articulo = m.SI_Num_Articulo
FULL JOIN SI_Consecutivo cs
ON c.SI_Num_Inventario = cs.SI_Num_Inventario
AND cs.SI_Estado = 0
WHERE c.SI_Num_Articulo = 201423 OR t.SI_Articulo = 201423
Basicallly I have combined both inserts into one Insert, which includes both of the columns , where you want a switch based on Case. Only one column out of SI_Ubicacion and SI_Ubicacion_Fisica will be set based on s.SI_OV value. Hope you got what I am saying,.
Note: I Could not execute this as I don't have any table structure/data with me. I have modified your query manually and posted it here.
Clarify your question. You have a select statement that returns a resultset of some number of rows. You propose to insert them into a table. You claim to need to use if/else (or similar) but it is not clear why. Your proposed insert statements differ by a single column - is that correct? If so, then you probably need to use 2 different insert statements - one to handle the non-null situation and one to handle the null situation. You cannot dynamically change the column list of the inserted table.
OTOH, perhaps you just want to swap the value inserted into the SI_Ubicacion column of the SI_Conteo table? If so, you can probably use isnull or coalesce in the select statement (much like you do now - just differently).

Join tables and groupby results based on user defined parameters in sql server 2008

I want to join two tables and group by the result based on a user defined parameter in Sql Server 2008. I tried the query below but it is not working. I appreciate if someone helps me to see my mistake and correct it for me. Regards.
Select TotalVolume= SUM(volume),
PrimGroup = r.PrimaryGroup, SnGroup = r.SecondaryGroup
from Requests r
inner join #Calculations c on
case #PrimaryId is not null then c.PrimaryGroup = r.PrimaryGroup end
and case #SecondaryId is not null then c.SecondaryGroup = r.SecondaryGroup end
and c.SrgId = r.SrgId
group by
case #PrimaryId is not null then r.PrimaryGroup end,
case #SecondaryId is not null then r.SecondaryGroup end
Try this:
Select TotalVolume= SUM(volume),
PrimGroup = r.PrimaryGroup, SnGroup = r.SecondaryGroup
from Requests r
inner join #Calculations c on
((#PrimaryId is null) or
(#PrimaryId is not null) and c.PrimaryGroup = r.PrimaryGroup)
and ((#SecondaryId is null) or
(#SecondaryId is not null) and c.SecondaryGroup = r.SecondaryGroup)
and c.SrgId = r.SrgId
group by
case when #PrimaryId is not null then r.PrimaryGroup end,
case when #SecondaryId is not null then r.SecondaryGroup end

Selecting column value based on another table

I have two tables, one of which contains many fields including fldANA and fldPROD and another table which contains the same two fields. Not all fldANA and fldPROD fields have a matching value in table 2 however and so I don't know as if I can really join the fields? The following is what my query currently looks like but it's returning 10's or 1000's more records than it is supposed to.
SELECT Line#, CastID,
(CASE WHEN #sRst1.PROD = FN_qryIDs.fldANA AND #sRst1.PROD =
FN_qryIDs.fldPROD
THEN FN_qryIDs.fldANA ELSE #sRst1.ANA END) AS ANA,
(CASE WHEN #sRst1.PROD = FN_qryIDs.fldANA AND #sRst1.PROD =
FN_qryIDs.fldPROD
THEN FN_qryIDs.fldCONN ELSE #sRst1.CONN END) AS CONN
INTO #sRst2
FROM #sRst1
WHERE CastID <> '' AND PROD <> '' AND ANA <> ''
Ehm, not sure about the source schema but hopefully this should at least get you on the right path.
SELECT R1.[Line#], R1.CastID
,ISNULL(Q.fldANA, R1.ANA) [ANA]
,ISNULL(Q.fldCONN, R1.CONN) [Conn]
FROM #sRst1 R1
LEFT JOIN FN_qryIDs Q ON Q.fldANA = R1.PROD
AND Q.fldPROD = R1.PROD
WHERE R1.CastID <> ''
AND R1.Prod <> ''
AND R1.ANA <> ''

SQL Query unable to return record

The following SQL works as expected if ProjectStatusType.Name is not null. Therefore I put the case statement which replace null value with 'Not specified'. What I am trying to do is to add a where statement to display ProjectStatusType.Name = 'Not Specified', but no data gets returned, although there is a record in database with null projectstatustype.name. Please advise; what is another way, or how can I fix the SQL query?
SELECT PersonResponsible.Name AS TeamLeaderName,
CASE
WHEN ProjectStatusType.Name IS NULL THEN 'Not Specified'
ELSE COALESCE(ProjectStatusType.Name, '')
END AS ProjectStatusName,
Project.ProjectTitle AS Title,
ProjectStatus.DateStatus,
Project.ProjectId,
Project.ContactName,
BusinessDivision.Name AS BusinessUnit,
BusinessUnit.Name AS WorkSection,
ProjectSubGroup.Name AS ProjectSubGroupName,
ProjectGroup.Name AS ProjectGroupName,
Project.DateRequested
FROM BusinessUnit
INNER JOIN BusinessDivision ON BusinessUnit.BusinessDivisionId = BusinessDivision.BusinessDivisionId
INNER JOIN ProjectCode ON BusinessUnit.BusinessUnitId = ProjectCode.BusinessUnitId
RIGHT OUTER JOIN Project
INNER JOIN ProjectSubGroup ON Project.ProjectSubGroupId = ProjectSubGroup.ProjectSubGroupId
INNER JOIN ProjectGroup ON ProjectSubGroup.ProjectGroupId = ProjectGroup.ProjectGroupId ON ProjectCode.ProjectCodeId = Project.ProjectCodeId
LEFT OUTER JOIN PersonResponsible ON Project.PersonResponsibleId = PersonResponsible.PersonResponsibleId FULL
OUTER JOIN ProjectStatusType
INNER JOIN ProjectStatus ON ProjectStatusType.ProjectStatusTypeId = ProjectStatus.ProjectStatusTypeId
AND ProjectStatus.ProjectStatusId IN
(SELECT MAX(ProjectStatusId) AS ProjectStatusId
FROM ProjectStatus
GROUP BY ProjectId) ON Project.ProjectId = ProjectStatus.ProjectId
WHERE ProjectStatus ProjectStatusType.Name ='Not Specified'
Here is a great chart from Itzik Ben-Gan on how SQL server processes a query. The order is different than how we write T-SQL.
Thus the solution by rutter might miss the empty string.
If I was doing this type of business logic alot, I would write a function that would take both the empty string or null value and return a string 'unknown'. Call this function in the query and filter by 'unknown'.
The example below creates a temporary table, loads the table with data, and returns both the empty string and null value converted to the adjust name 'Not Specified'.
I hope this helps.
I always refer to the logical processing chart when queries do not work the way I think they should.
Good luck
John
--
-- Logical query processing
--
-- From, Where, Group By, Having, Select (expression, distince, top), order by
-- sample table
create table #status
( id int identity(1,1),
name varchar(50) null
);
-- Sample data
insert into #status values
(''),
(null),
('www.craftydba.com');
-- Return rows with null or empty string
select
case when ltrim(name) = '' then 'Not Specified'
else coalesce(name, 'Not Specified') end as adjusted_named,
name
from #status
where
ltrim(name) = '' or
coalesce(name, 'Not Specified') = 'Not Specified';
Two points:
First, a CASE checking for null seems redundant to a COALESCE expression.
This should be simpler:
SELECT COALESCE(ProjectStatusType.Name, 'Not Specified') AS ProjectStatusName
Second, comparing to ProjectStatusType.Name (the value in your table) is not the same as comparing to ProjectStatusName (the value you selected).
Try a WHERE clause closer to this:
WHERE ProjectStatusName = 'Not Specified'