I'm about to build some sort of function or query where I can check if a certain record already exists in the database. The following rules apply:
The table has 6 columns
My yet-to-build-query has access to a complete row-object (all 6 values)
This query should find each row with at least 4 out of 6 corresponding values from the object I passed
Using MySQL
Is it even possible to build a query like this? My goal is to have a function which can return true if it's likely that a row like the passed object is already existing in the database.
Is my only option to make a query with multiple where-statements (where I try for each combination 4 different values)?
pseudo:
function getSimilarRow(Row_Object $row)
{
//select *
//from table_x
//where 4 out of 6 properties from object $row apply
}
You could use a case statement in the where clause for each property you are trying to match. If it meets the criteria then give the case statement a value of 1; if it doesn't then give it 0. The sum of the cases should then be >= 4.
I'm not that familiar with MySQL but the following will work (I knocked up a quick SQL Fiddle to show it working):
select * from SomeTable where
(case when propertyOne = 'value1' then 1 else 0 end) +
(case when propertyTwo = 'value2' then 1 else 0 end) +
(case when propertyThree = 'value3' then 1 else 0 end) +
(case when propertyFour = 'value4' then 1 else 0 end) +
(case when propertyFive = 'value5' then 1 else 0 end) +
(case when propertySix = 'value6' then 1 else 0 end) >= 4
Obviously you could change your logic in each clause if you'd prefer them to be likes or anything. You could even apply a weighting to each column by using something other than just 1 if you needed to get really creative.
Related
Hello i want to make a summary table where the filter is the segment and date
The columns will be the subtraction of count of two column in same table so far i have come up to this
select
case
when SEGMENT='champion'THEN SUM(SEGMENTED_DATE = '2022-10-14')-SUM(SEGMENTED_DATE='2022-10-07')
END as total_change_champion,
case
when SEGMENT='Hibernating'THEN SUM(SEGMENTED_DATE = '2022-10-14')-SUM(SEGMENTED_DATE='2022-10-07')
END as total_change_hibernate
from weekly_customer_RFM_TABLE;
This query is giving me null value for columns
select
SUM(SEGMENTED_DATE = '2022-10-14')-
SUM(SEGMENTED_DATE='2022-10-07')as total_changes_in_14th
From weekly_customer_RFM_TABLE
where
SEGMENT ='Hibernating'
This query is actually giving me the result. but when I am going to make a consolidated table using different segment subtraction i am getting null value in my result table.Kindly help me out
my sample data
which is i want to substract totalcount of 2022/10/14 - 2022/10/07 for each segment
image is not loading unfortunately
You must include the CASE expressions inside the aggregate functions:
SELECT COUNT(CASE WHEN SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-14' THEN 1 END) -
COUNT(CASE WHEN SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-07' THEN 1 END) AS total_change_champion,
COUNT(CASE WHEN SEGMENT = 'Hibernating' AND SEGMENTED_DATE = '2022-10-14' THEN 1 END) -
COUNT(CASE WHEN SEGMENT = 'Hibernating' AND SEGMENTED_DATE='2022-10-07' THEN 1 END) AS total_change_hibernate
FROM weekly_customer_RFM_TABLE;
For MySql this can be simplified to:
SELECT SUM(SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-14')-
SUM(SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-07') AS total_change_champion,
SUM(SEGMENT = 'Hibernating' AND SEGMENTED_DATE = '2022-10-14')-
SUM(SEGMENT = 'Hibernating' AND SEGMENTED_DATE='2022-10-07') AS total_change_hibernate
FROM weekly_customer_RFM_TABLE;
You may also use a WHERE clause to filter the table for only the SEGMENTs and SEGMENTED_DATEs that you want:
WHERE SEGMENT IN ('champion', 'Hibernating') AND SEGMENTED_DATE IN ('2022-10-07', '2022-10-14')
A snapshot of my DB
I want to get count of pcl_No present in a specified range( SUM(tv_land + tv_imp))
I have written a query but I am getting Invalid use of group error
select
count(CASE WHEN sum(tv_land+tv_imp) BETWEEN 0 AND 10000 THEN 1 END) as count0_10000
from
tax_l2006
where red_date = 0
GROUP BY pcl_no
Sample Output
0-10000 10000-20000 30000-40000 >40000
2 3 1 8
I think you just want:
select count(CASE WHEN tv_land + tv_imp BETWEEN 0 AND 10000 THEN 1 END) as count0_10000
from tax_l2006
where red_date = 0;
I would write this in MySQL more simply as:
select sum( (tv_land + tv_imp) between 0 and 10000 ) as count0_10000
from tax_l2006
where red_date = 0;
MySQL treats a true boolean as "1" in a numeric context and "0" for false, so summing the boolean is counting the number of times it is true.
You can follow the same pattern for the rest of the columns.
If pcl_no is not unique and you need to sum the values, then you would use a subquery:
select sum(total between 0 and 10000) as count0_10000
from (select pcl_no, sum(tv_land + tv_imp) as total
from tax_l2006
where red_date = 0
group by pcl_no
) p;
However, your data suggests that the column is unique, so the additional aggregation is not necessary.
First Stackoverflow question - so go easy on me :).
Hello, I am trying to flag items as "Attributed" using the following query that I have written. Essentially, if a patient ID has a PERSON_PROVIDER_RELATIONSHIP flag, they are given a 1 for that instance. If they have another type of flag (there are two other possible flags you can receive). Everything goes fine (the assigning of "1" to the instances of PERSON_PROVIDER_RELATIONSHIP), but then when I try to sum that custom column I created ("Attribution"), I get this error: (Column "Attribution" does not exist). I get this error whether I try to make another column that does the summing or when I add a "having" clause to the end where I state I only want to see records with a sum of >0. Any help would be appreciated here! I'm using MySQL to write this and am happy to provide any clarifying information.
select distinct c.empi_id as "Patient",
c.incurred_from_date as "Service Date",
(case when c.billing_organization_source_id IN ('xxxx','yyyy') then 1 else 0
end) as "In-Network Indicator",
(case when t.ref_record_type = 'PERSON_PROVIDER_RELATIONSHIP' then 1 else 0
end) as "Attribution",
(sum("Attribution") over (partition by c.empi_id)) as "Attribution Flag",
p.cleanprovidername as "Provider", t.ref_record_type
from ph_f_annotated_claim c
left outer join PH_F_Attribution_Component_Data_Point t
on t.empi_id = c.empi_id and t.population_id = c.population_id
inner join ph_d_personnel_alias a
on a.prsnl_id = t.prsnl_id
inner join xxxx_xxxx_xxxx_xxxx p
on a.prsnl_alias_id = p.NPI
where (c.bill_type_code like '33%'
or c.bill_type_code like '32%'
or c.bill_type_code like '033%'
or c.bill_type_code like '032%')
and c.source_description = 'MSSP Claims'
and c.incurred_from_date >= '2015-12-01'
and c.incurred_from_date <= '2017-01-31'
and c.population_id = '2feb2cb1-be55-4827-a21f-4e2ef1a40340'
and p.DegreeName IN ('MD','DO')
and a.prsnl_alias_type = 'NPI'
and p.PrimaryPHO = 'Yes'
group by c.empi_id, c.incurred_from_date, c.billing_organization_source_id,
p.cleanprovidername, t.ref_record_type
You can't use an aliased column name as an expression in the same SELECT clause. You have to do something like this:
sum(case when t.ref_record_type = 'PERSON_PROVIDER_RELATIONSHIP' then 1 else 0 end) over (partition by c.empi_id) as "Attribution Flag"
Working on a view that pulls from two table however in one table I need to select either one field or another depending on a third..it's the if else that has me stubbed.
Create view as
select
pens.PartNo,
pens.Title,
ranges.weight
if(pens.SpeacialOffer = 1 then pens.offer as Price else pens.Price)
from
pens, ranges
where
pens.penrange = ranges.id;
If the specialoffer is falged the the view needs to pull in the offer else it needs to pull in the Price.
What you need is a CASE operator:
CASE
WHEN condition
THEN value_a
ELSE value_b
END
So in your case:
CASE
WHEN pens.SpeacialOffer = 1
THEN pens.offer
ELSE pens.price
END
This replaces the entire column definition in your SELECT statement, so the whole view becomes:
Create View as
Select
pens.PartNo,
pens.Title,
ranges.weight,
Case
When pens.SpeacialOffer = 1
Then pens.offer
Else pens.price
End as Price
From
pens, ranges
Where
pens.penrange = ranges.id;
Use CASE, also converted the query to explicit join instead of implicit join
select pens.PartNo,
pens.Title,
ranges.weight,
(Case when
pens.SpeacialOffer = 1 then
pens.offer else pens.Price
end ) as Price
FROM pens,
JOIn ranges
ON pens.penrange = ranges.id;
Here's one way:
Create view as select
pens.PartNo,
pens.Title,
ranges.weight,
(pens.SpeacialOffer * pens.offer + (1 - pens.SpeacialOffer) * pens.price) as Price
from
pens,
ranges
where
pens.penrange = ranges.id;
I want to filter data based on an array, similar to "in" keyword in a query:
SELECT count(*) as number_of_records,
count(CASE WHEN result = 'SUCCESS' THEN 1 END) as successful_builds_no,
min(CASE WHEN result = 'FAILURE' THEN 0 ELSE 1 END) as is_success,
min(duration) as best_duration,
max(build_date) as build_date
FROM mdl_selenium_results
WHERE build_date in ('2014-03-13', '2014-03-12')
GROUP BY build_date
How to achieve that using Moodle DB api??
If you are creating an SQL query to use within Moodle, you could just use the IN keyword, exactly as you have done in the example.
Alternatively, to make it a bit more cross-DB compatible, and to make your queries run a bit faster when there is only one item in the list, you can write:
list($dsql, $dparam) = $DB->get_in_or_equal(array('2014-03-13', '2014-03-12'), SQL_PARAMS_NAMED);
$sql = "SELECT count(*) as number_of_records,
count(CASE WHEN result = 'SUCCESS' THEN 1 END) as successful_builds_no,
min(CASE WHEN result = 'FAILURE' THEN 0 ELSE 1 END) as is_success,
min(duration) as best_duration,
max(build_date) as build_date
FROM {selenium_results}
WHERE build_date $dsql
GROUP BY build_date";
$result = $DB->get_records_sql($sql, $dparams);
OR, if you just want to get all the matching records from the given table (and then worry about doing the calculations in PHP), you could write:
$result = $DB->get_records_list('selenium_results', 'build_date', array('2014-03-13', '2014-03-12'));
(I've not run any of the code above, so apologies for any typos)