MYSQL CASE/IF over a value selected with SELECT - mysql

I'd like to run a CASE statement or IF on the COUNT_A returned by the select query below and set the value of a variable A_VAL.
SELECT A_DATE, COUNT(A_INS_NAM) AS COUNT_A
FROM TABLE1
WHERE A_INS_NAM IN
(
SELECT A_INS_NAM FROM IWD
WHERE I_ID IN
(
SELECT IM_ID FROM TIM WHERE IM_ID = (
SELECT T_ID FROM TWS WHERE TN = 'abced')
)
) AND A_DATE BETWEEN '2014-01-01' AND '2015-05-01' AND A_INS_NAM NOT LIKE '%pk%'
I'd like the output to have 2 columns namely A_DATE, A_VAL. The value of A_VAL gets set based on
If COUNT_A = 10, then A_VAL = 1
If COUNT_A = 20, then A_VAL = 2
If COUNT_A between 30 & 50, then A_VAL = 3
If COUNT_A > 50, then A_VAL = 5
Could I get someone's help please?

You should use joins instead of sub queries for better performance something like below, also you are using an aggregate function without providing grouping criteria so it will result as a single row for this i have added GROUP BY t.A_DATE in below query
SELECT
t.A_DATE,
CASE
WHEN COUNT(t.A_INS_NAM) = 10 THEN 1
WHEN COUNT(t.A_INS_NAM) = 20 THEN 2
WHEN COUNT(t.A_INS_NAM) BETWEEN 30 AND 50 THEN 3
WHEN COUNT(t.A_INS_NAM) > 50 THEN 5
ELSE 'some value'
END AS A_VAL
FROM
TABLE1 t
JOIN IWD t1 ON(t.A_INS_NAM = t1.A_INS_NAM)
JOIN TIM t2 ON(t1.IWD = t2.IM_ID)
JOIN TWS t3 ON(t2.IM_ID = t3.T_ID )
WHERE t3.TN = 'abced'
AND t.A_DATE BETWEEN '2014-01-01' AND '2015-05-01'
AND t.A_INS_NAM NOT LIKE '%pk%'
GROUP BY t.A_DATE

Related

Mysql problem to see if two selects are the same

SELECT table_grouping_code, gui_field_code, gui_interface_id, dictionary_code, property_name, position INTO #test
FROM table_grouping_layout
WHERE company_code = "TEST";
SELECT table_grouping_code, gui_field_code, gui_interface_id, dictionary_code, property_name, position INTO #doximtrx
FROM table_grouping_layout
WHERE company_code = "DOXIMTRX";
select #test = #doximtrx;
I tried this, that seems very logica to me, but mysql says: ERROR CODE 1222: the used select statement have a different number of columns. How can it be possible?? I copied the query, only changing the code.
Example of data in the table
You are trying to select many columns into a single variable. The correct syntax for that part of your query is:
SELECT
GROUP_CONCAT(table_grouping_code ORDER BY table_grouping_code)
, GROUP_CONCAT(gui_field_code ORDER BY gui_field_code)
, GROUP_CONCAT(gui_interface_id ORDER BY gui_interface_id)
, GROUP_CONCAT(dictionary_code ORDER BY dictionary_code)
, GROUP_CONCAT(property_name ORDER BY property_name)
, GROUP_CONCAT(position ORDER BY position)
FROM
table_grouping_layout
WHERE
company_code = 'TEST'
INTO
#t1, #t2, #t3, #t4, #t5, #t6;
SELECT
GROUP_CONCAT(table_grouping_code ORDER BY table_grouping_code)
, GROUP_CONCAT(gui_field_code ORDER BY gui_field_code)
, GROUP_CONCAT(gui_interface_id ORDER BY gui_interface_id)
, GROUP_CONCAT(dictionary_code ORDER BY dictionary_code)
, GROUP_CONCAT(property_name ORDER BY property_name)
, GROUP_CONCAT(position ORDER BY position)
FROM
table_grouping_layout
WHERE
company_code = 'DOXIMTRX'
INTO
#d1, #d2, #d3, #d4, #d5, #d6;
How to compare results is a different story:
SELECT ifNull(
#t1 = #d1
and #t2 = #d2
and #t3 = #d3
and #t4 = #d4
and #t5 = #d5
and #t6 = #d6
, false
) as result;
TEST DATA:
select * from table_grouping_layout;
table_grouping_code
gui_field_code
gui_interface_id
dictionary_code
property_name
position
company_code
1
2
3
4
5
6
DOXIMTRX
1
3
3
4
5
6
TEST
1
1
3
4
5
6
DOXIMTRX
1
2
3
4
5
6
TEST
QUERY RESULT:
result
0
Variables are meant to hold one value. Neither one row nor one column nor one table.
Comparing two data sets can be achieved with a combination of UNIONand EXCEPT or with a full outer join. Unfortunately, MySQL does neither support EXCEPT nor FULL OUTER JOIN.
Here is a workaround:
with t as (select * from table_grouping_layout where company_code = 'TEST')
, d as (select * from table_grouping_layout where company_code = 'DOXIMTRX')
select 'MISMATCH' as status, t.position
from table_grouping_layout t
join table_grouping_layout d
on t.position = d.position
and not
(
t.table_grouping_code <=> t.table_grouping_code and
t.gui_field_code <=> t.gui_field_code and
t.gui_interface_id <=> t.gui_interface_id and
t.dictionary_code <=> t.dictionary_code and
t.property_name <=> t.property_name
)
union all
select 'TEST MISSING' as status, position
from d
where position not in (select position from t)
union all
select 'DOXIMTRX MISSING' as status, position
from t
where position not in (select position from d)
order by position;
Another approach using aggregation:
select
position,
case
when sum(company_code = 'TEST') = 0 then 'TEST MISSING'
when sum(company_code = 'DOXIMTRX') = 0 then 'DOXIMTRX MISSING'
when not
(
max(table_grouping_code) <=> min(table_grouping_code) and count(table_grouping_code) in (0,2)
max(gui_field_code) <=> min(gui_field_code) and count(gui_field_code) in (0,2)
max(gui_interface_id) <=> min(gui_interface_id) and count(gui_interface_id) in (0,2)
max(dictionary_code) <=> min(dictionary_code) and count(dictionary_code) in (0,2)
max(property_name) <=> min(property_name) and count(property_name) in (0,2)
) then 'MISMATCH'
else 'MATCH' end as status
from table_grouping_layout
where company_code in ('TEST', 'DOXIMTRX')
group by position
order by position;

MS SQL query with multiple search criteria across rows

I have below table and SQL query written, this query should not return any result but its returning ID = 1 , what is wrong with the SQL query? Can anyone please help?
** Note balance data type is decimal rest are varchar
ID code balance level
1 C 150.00
1 P 40027.42 F
1 P 40027.42 F
select distinct ID from table
(
(code = 'P' and balance = 40027.42 and level = 'F') or
(code = 'C' and balance = 151.00 )
)
group by ID
having count(ID) >=2
If you do not want to count the same code twice, you can use count(distinct code):
select ID
from t
where (code = 'P' and balance = 40027.42 and level = 'F')
or (code = 'C' and balance = 151.00 )
group by ID
having count(distinct code) >=2
If you want to only count a distinct set of values once, you can use a derived table/subquery to select distinct rows:
select ID
from (
select distinct id, code, balance, level
from t
) as s
where (code = 'P' and balance = 40027.42 and level = 'F')
or (code = 'C' and balance = 151.00 )
group by ID
having count(ID) >=2
rextester demo for both: http://rextester.com/LBKO57534

Can I replace this loop in a sql server query

I have a list of items, sorted by date descending, and it checks them like this:
counted = 0
DateToCheck = now
foreach(item)
{
if( abs(item.date - DateToCheck) > 14 days )
{
counted++
}
DateToCheck = item.date
}
The goal is to get a count of items on the list that did not occur within 14 days of the previous item.
The table is just a list of dates, like this:
index ItemDate
307000 2017-08-17
307001 2017-04-25
307002 2016-09-23
307003 2016-08-26
307004 2016-04-30
307005 2016-03-01
307006 2016-03-01
The result here should be a count of 6, the last one is ignored since it is within 14 days of the one before.
You can use this query.
DECLARE #item TABLE([index] int, [date] DATETIME)
INSERT INTO #item
VALUES( 307006 ,'2017-08-17'),
(307005 ,'2017-04-25'),
(307004 ,'2016-09-23'),
(307003 ,'2016-08-26'),
(307002 ,'2016-04-30'),
(307001 ,'2016-03-01'),
(307000 ,'2016-03-01')
SELECT
count(*)
FROM #item T1
OUTER APPLY (
SELECT TOP 1 *
FROM #item T2
WHERE T2.[index] < T1.[index]
ORDER BY T2.[index] DESC) T
WHERE DATEDIFF(DAY, T.[date], T1.[date]) > 14
You can use this query if you do not have a ID column. Use ID column directly if you have one.
;WITH TBL AS (
SELECT ROW_NUMBER() OVER(ORDER BY ItemDate ASC) Id, ItemDate FROM TABLE_NAME
)
SELECT COUNT(a.ItemDate) FROM TBL a INNER JOIN TBL b ON b.ID = a.ID + 1 WHERE DATEDIFF(d, a.CreatedOn, b.CreatedOn) > 14;
With ID column, query changes to
SELECT COUNT(a.ItemDate) FROM TABLE_NAME a INNER JOIN TABLE_NAME b ON b.ID = a.ID + 1 WHERE DATEDIFF(d, a.CreatedOn, b.CreatedOn) > 14;

Sum of two counts from different table with different conditions

Basically I need to merge these into one single query:
SELECT COUNT( DISTINCT id ) AS totalRows1
FROM other_events WHERE status = "approved"
AND Location = 1
SELECT COUNT( DISTINCT Id ) AS totalRows2
FROM core_events WHERE Status = "Active"
AND Location_id = 1
When I do it like below, if there is no event with Location_id = 1 query returns 0. In that condition I need it to return the count of the first table only.
SELECT COUNT( DISTINCT t1.id ) + COUNT( DISTINCT t2.Id ) AS total
FROM other_events AS t1, core_events AS t2
WHERE t1.status = "approved"
AND t1.Location = 1
AND t2.Location_id = 1
AND t2.Status = 'Active'
ps. column names are exactly like above
Use a UNION statement to merge the result like this:
SELECT SUM(total) FROM (
SELECT COUNT(DISTINCT id) AS total
FROM other_events
WHERE (status = "approved" AND Location = 1)
UNION ALL
SELECT COUNT(DISTINCT Id) AS total
FROM core_events
WHERE (Location_id = 1 AND Status = 'Active')
) union_result

Coalesce whole records in MySQL

I'm currently coallescing fields individually in MySQL queries, but I would like to coalesce whole records.
Is this possible?
SELECT la.id,
COALESCE(( SELECT name FROM lookup_changed l0,
( SELECT MAX(id) id
FROM lookup_changed
WHERE lookup_id = 26
) l1
WHERE l0.id = l1.id
), la.name) name,
COALESCE(( SELECT msisdn FROM lookup_changed l0,
( SELECT MAX(id) id
FROM lookup_changed
WHERE lookup_id = 26
) l1
WHERE l0.id = l1.id
), la.msisdn) msisdn
FROM lookup_added la
WHERE la.id = 26
#Alma Do - the pseudo-SQL is:
SELECT la.id,
MULTICOALESCE(( SELECT <name, msisdn> FROM lookup_changed l0,
( SELECT MAX(id) id
FROM lookup_changed
WHERE lookup_id = 26
) l1
WHERE l0.id = l1.id
), <la.name, la.msisdn>) <name, msisdn>
FROM lookup_added la
WHERE la.id = 26
Since COALESCE() "return[s] the first non-NULL argument", it sounds like you want to retreive the "first non-NULL result from a set for queries":
-- syntax error
SELECT COALESCE(
SELECT a FROM ta,
SELECT b FROM tb
);
-- roughly equates to
( SELECT a AS val FROM ta WHERE a IS NOT NULL ORDER BY a LIMIT 1 )
UNION
( SELECT b AS val FROM tb WHERE b IS NOT NULL ORDER BY b LIMIT 1 )
ORDER BY val LIMIT 1 ;
Comments:
I added ORDER BY clauses, otherwise "first row" means nothing
the inner LIMIT 1 clauses are optional (but allow early trimming of sub-results)
the parenthesis around the sub queries are mandatory