Case Statement that runs sql - sql

I am applying a mask to data and believe the best way is to use a Case Statement. However, I need the case statement to run a sub query. When I pull data, it will either be a number or appear as 99999999999v999b:99999999999v999-
Using
TO_NUMBER(REGEXP_REPLACE(RD.subm_quantity, '^(\d+)(-)?$', '\2\1'))/1000 as "Submitted_Quantity"
This will convert it to a number. So if 00000000100000 is present, it will convert to 100
However, I need a case to not divide when not needed. To determine if I need to divide, I need to add a rule in the below sql:
if the result is 99999999999v999b:99999999999v999-, apply the conversion;
if not, just output RD.subm_quantity.
How can I get a case statement to run a query?
Running in TOAD for Oracle:
select m.mask
FROM Valiuser.ivd_mapping m,
Valiuser.ivd_mappingset s,
Valiuser.ivd_mapping_record r,
Valiuser.ivd_transaction_file tf,
VALIUSER.ivd_transaction_record_details RD
WHERE s.mappingset_id = r.mappingset_id
AND r.mapping_record_id = m.mapping_record_ID
AND m.repository_column_id = '34'
AND s.mappingset_id = tf.MAPPINGSET_ID
AND rd.file_id = tf.file_id
AND rd.TRANSACTION_RECORD_ID =

If the mask and original subm_quantity are both available from the query you showed, which seems to be the same as that includes the rd table you're referencing in the conversion, then I think you want something like this:
case when m.mask = '99999999999v999b:99999999999v999-'
then TO_NUMBER(REGEXP_REPLACE(rd.subm_quantity, '^(\d+)(-)?$', '\2\1')) / 1000
else rd.subm_quantity
end as "Submitted_Quantity"
rather than a subquery. So plugged into your current query that would make it:
SELECT
case when m.mask = '99999999999v999b:99999999999v999-'
then TO_NUMBER(REGEXP_REPLACE(rd.subm_quantity, '^(\d+)(-)?$', '\2\1')) / 1000
else rd.subm_quantity
end as "Submitted_Quantity"
FROM
Valiuser.ivd_mapping m,
Valiuser.ivd_mappingset s,
Valiuser.ivd_mapping_record r,
Valiuser.ivd_transaction_file tf,
Valiuser.ivd_transaction_record_details rd
WHERE
s.mappingset_id = r.mappingset_id
AND r.mapping_record_id = m.mapping_record_ID
AND m.repository_column_id = '34'
AND s.mappingset_id = tf.mappingset_id
AND rd.file_id = tf.file_id
AND rd.Transaction_Record_Id = <?>
or with modern join syntax instead of the old version, something like:
SELECT
case when m.mask = '99999999999v999b:99999999999v999-'
then TO_NUMBER(REGEXP_REPLACE(rd.subm_quantity, '^(\d+)(-)?$', '\2\1')) / 1000
else rd.subm_quantity
end as "Submitted_Quantity"
FROM Valiuser.ivd_mapping m
JOIN Valiuser.ivd_mapping_record r ON r.mapping_record_id = m.mapping_record_ID
JOIN Valiuser.ivd_mappingset s ON s.mappingset_id = r.mappingset_id
JOIN Valiuser.ivd_transaction_file tf ON tf.mappingset_id = s.mappingset_id
JOIN Valiuser.ivd_transaction_record_details rd ON rd.file_id = tf.file_id
WHERE m.repository_column_id = '34'
AND rd.transaction_record_id = <?>

Related

Convert MS Access Update Query to SQL Query

I have an MS Access Query:
'''UPDATE MyFloridaNetDataDump INNER JOIN RepoVoipAcsNonRecurring ON
'''MyFloridaNetDataDump.service_modified = RepoVoipAcsNonRecurring.Validation
'''SET RepoVoipAcsNonRecurring.Invoice = MyFloridaNetDataDump.Invoice_modified,
'''RepoVoipAcsNonRecurring.Amount = '''Round(MyFloridaNetDataDump.billable_charge*RepoVoipAcsNonRecurring.Percentage,2),
'''RepoVoipAcsNonRecurring.Billing Cycle = MyFloridaNetDataDump.bill_cycle;
I need to convert it to SQL, which I'm using in a .net application.
I have been able to convert most of the query, but when I try to perform the multiplication I get errors depending on what I leave in. Meaning if I take the ROUND function out it doesn't like the * multiplication. If I remove the multiplication line, the query runs.
'''UPDATE MyFloridaNetDataDump
'''SET MyFloridaNetDataDump.InvoiceModified = RepoVoipAcsNonRecurring.Invoice,
'''MyFloridaNetDataDump.BillableCharge * RepoVoipAcsNonRecurring.Percentage = '''RepoVoipAcsNonRecurring.Amount,
'''MyFloridaNetDataDump.BillCycle = RepoVoipAcsNonRecurring.BillingCycle
'''FROM RepoVoipAcsNonRecurring
'''WHERE MyFloridaNetDataDump.ServiceModified = RepoVoipAcsNonRecurring.Validation
I think you inverse all of your set columns
I would suggest you to do like this
UPDATE r
SET
Invoice = m.InvoiceModified,
Amount = Round(m.billablecharge*r.Percentage,2),
[BillingCycle] = m.billCycle
FROM
MyFloridaNetDataDump m
INNER JOIN RepoVoipAcsNonRecurring r ON m.serviceModified = r.Validation

How to dynamic, handle nested WHERE AND/OR queries using Rails and SQL

I'm currently building a feature that requires me to loop over an hash, and for each key in the hash, dynamically modify an SQL query.
The actual SQL query should look something like this:
select * from space_dates d
inner join space_prices p on p.space_date_id = d.id
where d.space_id = ?
and d.date between ? and ?
and (
(p.price_type = 'monthly' and p.price_cents <> 9360) or
(p.price_type = 'daily' and p.price_cents <> 66198) or
(p.price_type = 'hourly' and p.price_cents <> 66198) # This part should be added in dynamically
)
The last and query is to be added dynamically, as you can see, I basically need only one of the conditions to be true but not all.
query = space.dates
.joins(:price)
.where('date between ? and ?', start_date, end_date)
# We are looping over the rails enum (hash) and getting the key for each key value pair, alongside the index
SpacePrice.price_types.each_with_index do |(price_type, _), index|
amount_cents = space.send("#{price_type}_price").price_cents
query = if index.positive? # It's not the first item so we want to chain it as an 'OR'
query.or(
space.dates
.joins(:price)
.where('space_prices.price_type = ?', price_type)
.where('space_prices.price_cents <> ?', amount_cents)
)
else
query # It's the first item, chain it as an and
.where('space_prices.price_type = ?', price_type)
.where('space_prices.price_cents <> ?', amount_cents)
end
end
The output of this in rails is:
SELECT "space_dates".* FROM "space_dates"
INNER JOIN "space_prices" ON "space_prices"."space_date_id" = "space_dates"."id"
WHERE "space_dates"."space_id" = $1 AND (
(
(date between '2020-06-11' and '2020-06-11') AND
(space_prices.price_type = 'hourly') AND (space_prices.price_cents <> 9360) OR
(space_prices.price_type = 'daily') AND (space_prices.price_cents <> 66198)) OR
(space_prices.price_type = 'monthly') AND (space_prices.price_cents <> 5500)
) LIMIT $2
Which isn't as expected. I need to wrap the last few lines in another set of round brackets in order to produce the same output. I'm not sure how to go about this using ActiveRecord.
It's not possible for me to use find_by_sql since this would be dynamically generated SQL too.
So, I managed to solve this in about an hour using Arel with rails
dt = SpaceDate.arel_table
pt = SpacePrice.arel_table
combined_clauses = SpacePrice.price_types.map do |price_type, _|
amount_cents = space.send("#{price_type}_price").price_cents
pt[:price_type]
.eq(price_type)
.and(pt[:price_cents].not_eq(amount_cents))
end.reduce(&:or)
space.dates
.joins(:price)
.where(dt[:date].between(start_date..end_date).and(combined_clauses))
end
And the SQL output is:
SELECT "space_dates".* FROM "space_dates"
INNER JOIN "space_prices" ON "space_prices"."space_date_id" = "space_dates"."id"
WHERE "space_dates"."space_id" = $1
AND "space_dates"."date" BETWEEN '2020-06-11' AND '2020-06-15'
AND (
("space_prices"."price_type" = 'hourly'
AND "space_prices"."price_cents" != 9360
OR "space_prices"."price_type" = 'daily'
AND "space_prices"."price_cents" != 66198)
OR "space_prices"."price_type" = 'monthly'
AND "space_prices"."price_cents" != 5500
) LIMIT $2
What I ended up doing was:
Creating an array of clauses based on the enum key and the price_cents
Reduced the clauses and joined them using or
Added this to the main query with an and operator and the combined_clauses

Issue With SQL Pivot Function

I have a SQL query where I am trying to replace null results with zero. My code is producing an error
[1]: ORA-00923: FROM keyword not found where expected
I am using an Oracle Database.
Select service_sub_type_descr,
nvl('Single-occupancy',0) as 'Single-occupancy',
nvl('Multi-occupancy',0) as 'Multi-occupancy'
From
(select s.service_sub_type_descr as service_sub_type_descr, ch.claim_id,nvl(ci.item_paid_amt,0) as item_paid_amt
from table_1 ch, table_" ci, table_3 s, table_4 ppd
where ch.claim_id = ci.claim_id and ci.service_type_id = s.service_type_id
and ci.service_sub_type_id = s.service_sub_type_id and ch.policy_no = ppd.policy_no)
Pivot (
count(distinct claim_id), sum(item_paid_amt) as paid_amount For service_sub_type_descr IN ('Single-occupancy', 'Multi-occupancy')
)
This expression:
nvl('Single-occupancy',0) as 'Single-occupancy',
is using an Oracle bespoke function to say: If the value of the string Single-occupancy' is not null then return the number 0.
That logic doesn't really make sense. The string value is never null. And, the return value is sometimes a string and sometimes a number. This should generate a type-conversion error, because the first value cannot be converted to a number.
I think you intend:
coalesce("Single-occupancy", 0) as "Single-occupancy",
The double quotes are used to quote identifiers, so this refers to the column called Single-occupancy.
All that said, fix your data model. Don't have identifiers that need to be quoted. You might not have control in the source data but you definitely have control within your query:
coalesce("Single-occupancy", 0) as Single_occupancy,
EDIT:
Just write the query using conditional aggregation and proper JOINs:
select s.service_sub_type_descr, ch.claim_id,
sum(case when service_sub_type_descr = 'Single-occupancy' then item_paid_amt else 0 end) as single_occupancy,
sum(case when service_sub_type_descr = 'Multi-occupancy' then item_paid_amt else 0 end) as multi_occupancy
from table_1 ch join
table_" ci
on ch.claim_id = ci.claim_id join
table_3 s
on ci.service_type_id = s.service_type_id join
table_4 ppd
on ch.policy_no = ppd.policy_no
group by s.service_sub_type_descr, ch.claim_id;
Much simpler in my opinion.
for column aliases, you have to use double quotes !
don't use
as 'Single-occupancy'
but :
as "Single-occupancy",

getting error The multi-part identifier "e.EpVisitCount" could not be bound. in sql server

I am working on converting mysql query to sql server, but when i run the query it gives me error The multi-part identifier "e.EpVisitCount" could not be bound. , here i have posted my both query can you please look into it, why it gives me error in sql server ?
Mysql Query(Working Fine) :
UPDATE
tb_EpVisitRange as v left JOIN tb_Episode as e ON (v.company_id = e.CustID) AND (v.CMW = e.CMW)
SET
e.EpVisitCount = If(PayerType='NonEp',0,If(LUPA=1,0,v.High)),
e.VisitAlert = If( e.TotVisits > v.High,1,NULL)
where UploadID = '23'
SQl Query(Getting Error) :
UPDATE v
SET
e.EpVisitCount = IIF(PayerType='NonEp',0,IIF(LUPA=1,0,v.High)),
e.VisitAlert = IIF( e.TotVisits > v.High,1,NULL)
FROM tb_EpVisitRange v
JOIN tb_Episode as e ON (v.company_id = e.CustID) AND (v.CMW = e.CMW)
where UploadID = '613'
You seem to want to update e rather than v. So, you might try:
UPDATE e
SET EpVisitCount = (CASE WHEN PayerType = 'NonEp' THEN 0
WHEN LUPA = 1 THEN 0
ELSE v.High
END),
VisitAlert = (CASE WHEN e.TotVisits > v.High THEN 1 END)
FROM tb_Episode e JOIN
tb_EpVisitRang v
ON v.company_id = e.CustID AND v.CMW = e.CMW
WHERE UploadID = '613';
Notes:
The problem appears to be the table alias used for the update.
SQL Server only allows updating one table in a statement. There is no need to qualify the column names for the SET.
Use CASE for conditions. It is the ANSI standard and supported by almost all database.
This is especially true for nested expressions. CASE supports multiple conditions.
You are updating e, so I made that the first table in the FROM clause. I find that logic easier to follow.
You should qualify UploadId.

Trying to get better at understand sql queries

I'm a new developer in a corporate IT group. I feel completely lost looking at alot of the sql that's written in our code. There are many queries that are literally hundreds of lines long. Here's an example of a "smaller" one (the table/field names have been modified, but the structure is the same). Do I just suck at this or is it really difficult to understand? How would you approach rewriting it to be more manageable/understandable?
SELECT pd.commission_header_id COMMISSION_HEADER_ID
,pd.sales_rep_id DIRECT_SALESREP_ID
,pd.org_id ORG_ID
,LEAST(100, innview.spilt_percent) SPLIT_PCT
,pd.source SOURCE
,pd.application APPLICATION
,pd.plan PLANE
,pd.pay_freq pay_freq
,pd.emp_app_count EMP_APP_COUNT
,pd.client_name CLIENT_NAME
,pd.fed_id FED_ID
,pd.off_nbr OFF_NBR
,pd.payroll_num payroll_num
,TO_DATE(pd.product_start_date,'DD-MON-YY') PRODUCT_START_DATE
,pd.loss_date LOSS_DATE
,pd.acquisitions_ind ACQUISITIONS_IND
,pd.source_of_business SOURCE_OF_BUSINESS
,pd.prev_br_clt_nbr PREV_BR_CLT_NBR
,pd.previous_method PREVIOUS_METHOD
,pd.natl_acct_number NATL_ACCT_NUMBER
,pd.product_name PRODUCT_NAME
,pd.lost_reason LOST_REASON
,pd.client_id CLIENT_ID
,pd.lead_nbr LEAD_NBR
,pd.processed_date PROCESSED_DATE
,pd.rep_type REP_TYPE
,pd.order_number ORDER_NUMBER
,pd.conversion_type CONVERSION_TYPE
,SUBSTR(original_billing_info,1,INSTR(original_billing_info,'|',1,1)-1) BILLING_APPLICATION
,SUBSTR(original_billing_info,INSTR(original_billing_info,'|',1,1)+1,INSTR(original_billing_info,'|',1,2)-INSTR(original_billing_info,'|',1,1)-1) BILLING_CODE
,SUBSTR(original_billing_info,INSTR(original_billing_info,'|',1,2)+1,INSTR(original_billing_info,'|',1,3)-INSTR(original_billing_info,'|',1,2)-1) BILLING_PROD_GRP_NM
,SUBSTR(original_billing_info,INSTR(original_billing_info,'|',1,3)+1) BILLING_FIELD_FOR_CHRGS
,SUBSTR(original_discount_info,1,INSTR(original_discount_info,'|',1,1)-1) DISCOUNT_APPLICATION
,SUBSTR(original_discount_info,INSTR(original_discount_info,'|',1,1)+1,INSTR(original_discount_info,'|',1,2)-INSTR(original_discount_info,'|',1,1)-1) DISCOUNT_CODE
,CASE WHEN (NVL(innview.trans,0)) = 0
THEN 0
ELSE ( NVL(innview.comm,0)) / ( NVL(innview.trans,0))
END ORIGINAL_COMM_PCT
,pd.record_type RECORD_TYPE
,innview.trans PAR_SUM
,NVL(ocp.oic_clients_pk, pxmis.oic_client_products_pk_seq.nextval) CLIENT_PRODUCT_ID
,pd.associated_with ASSOCIATED_WITH_ID
,pd.refferal_sale refferal_sale
,pd.parent_client_nbr PARENT_CLIENT_NBR
FROM pxmis.pd_commissions pd
JOIN pxmis.oic_lookback_months olm ON (pd.application = olm.application
AND pd.plan = olm.plan)
LEFT OUTER JOIN pxmis.oic_client_products ocp ON (pd.off_nbr = ocp.off_nbr
AND pd.payroll_num = ocp.payroll_num
AND pd.application = ocp.application
AND pd.plan = ocp.plan
AND pd.sales_rep_id = ocp.direct_salesrep_id
AND pd.source = ocp.source
AND ocp.record_type in (:1,:2)
AND NVL(pd.refferal_sale,'NON REF') = NVL(ocp.refferal_sale,'NON REF'))
JOIN (SELECT SUM(NVL(transaction_amount,0)) as trans
,SUM(commission_amount) as comm
,SUM(pd2.oic_split_percent) as spilt_percent
,pd2.application as application
,pd2.plan as code
,pd2.sales_rep_id as sales_rep_id
,pd2.payroll_num as client_nbr
,LPAD(pd2.off_nbr,4,0) as off_nbr
FROM pxmis.pd_commissions pd2
JOIN pxmis.oic_lookback_months olm2 ON (pd2.application = olm2.application
AND pd2.plan = olm2.plan)
WHERE CASE WHEN (pd2.record_type IN ('SAPBA','ASAPBA'))
THEN pd2.SUB_RECORD_TYPE
ELSE 'Eligible'
END = 'Eligible'
AND pd2.record_type IN ('SDBDA', 'ASDBDA',
decode(:3,'CHCST','SAPBA',NULL),
decode(:4,'CHCST','ASAPBA',NULL),
'SAPBP','ASAPBP')
AND pd2.processed_date BETWEEN ADD_MONTHS(:5,(olm2.lookback_months_high - 1) * -1) AND ADD_MONTHS(:6, (olm2.lookback_months_low - 2) * -1) - 1
and :7 between olm2.effective_start_date and olm2.effective_end_date
and olm2.function_type = :8
GROUP BY pd2.application
,pd2.plan
,pd2.sales_rep_id
,pd2.payroll_num
,LPAD(pd2.off_nbr,4,0)) innview on (innview.application = pd.application
AND innview.code = pd.plan
AND innview.sales_rep_id = pd.sales_rep_id
AND innview.client_nbr = pd.payroll_num
AND innview.off_nbr = LPAD(pd.off_nbr,4,0))
WHERE :9 BETWEEN olm.effective_start_date AND olm.effective_end_date
AND pd.sales_rep_id <> -3
AND pd.record_type IN ('SAPBP','ASAPBP')
AND NOT EXISTS(SELECT 'X'
FROM pxmis.pd_commissions pd3
WHERE pd3.application = pd.application
AND pd3.plan = pd.plan
AND pd3.sales_rep_id = pd.sales_rep_id
AND pd3.payroll_num = pd.payroll_num
AND (pd3.record_type in ('CHCST','ACHCST')
or ( pd3.record_type = 'SAPBA'
and pd3.sub_record_type = 'Chargeback')))
AND pd.commission_header_id = (SELECT MAX(pd4.commission_header_id)
FROM pxmis.pd_commissions pd4
WHERE pd4.application = pd.application
AND pd4.plan = pd.plan
AND pd4.sales_rep_id = pd.sales_rep_id
AND pd4.payroll_num = pd.payroll_num
AND pd4.record_type = pd.record_type)
AND olm.function_type = :10
AND pd.processed_date BETWEEN ADD_MONTHS(:11,(olm.lookback_months_high - 1) * -1) AND ADD_MONTHS(:12, (olm.lookback_months_low - 2) * -1) - 1
AND pd.source = :13
AND pay_freq IS NOT NULL
AND pd.core_conversion_revenue IS NULL;
Sidenote: (Due to my reputation I can not make comments:)
This is my first time answering. Hopefully it will help.
I do not know if it might help, but most of the SQL script (maybe all of it), can be rewritten in other languages. For example you can use JOINS in C# .NET LINQ.
But a way I usually separate the SQL script, is to look for the keywords and see what they do. Do not confuse the big letters from the small ones.
The SELECT function selects all of the datas.
The TO_DATE function says that it will convert the a string to date (source: http://www.techonthenet.com/oracle/functions/to_date.php)
The LEAST function returns the smallest number between the variables you have as parameters (Source: http://www.techonthenet.com/oracle/functions/least.php)
You can do this for every function, and try and grasp what the script does.
I think you could end the script here: FROM pxmis.pd_commissions pd
Also I have seen that you do a JOIN.
Here you could properly make a new script and run that code.
Right now I might not be able to make it more readable. (Mostly because I work with .NET C# linqs).
Again hopefully it helped in some way.