Finding sum conditionally mysql - mysql

i have a table test containing columns as:
id
amt
date(yyyy-mm-dd)
and values as
1 10 2017-08-09
1 20 2017-08-10
2 10 2017-09-11
Now i need to sum all the amt for a particular id only if the MONTH(date) = value1 AND YEAR(date) = value2.
I tried the following but am not getting the desired result.
#value1 = 8
#value2 = 2017
#id = 1
SELECT SUM(CASE WHEN MONTH(date) = #value1 AND YEAR(date)= #value2
THEN test.amt
ELSE 0 END) netAmt
FROM test
WHERE id = #id
Desired result should be 30 . However i get 0 .
Any help is appriciated.

this may help you,
select sum(amt) as amt from test where month(date)=8 and year(date)='2017' and id=1;

sql like this:
select sum(amt) from test where date like '2017-08%'

Have you tried the following?
SET #value1 = 8;
SET #value2 = 2017;
SET #id = 1;
select sum(`amt`) as total from test where `id` = #id and MONTH(`date`) = #value1 AND YEAR(`date`)= #value2;

I was working on MySql Workbench and was trying to select three set statements all at a time.
The result was that only the 1st set statement was being set. Executing them separately worked.

Related

SQL Subquery IN SELECT [Symfony3]

I Have Table Actions with the following fields :
idAction
Cloture
Date
I'd Like to loop through and display a list of all idAction In my DB + idAction with Cloture = 0 Group By the same Date (both of them).
I tried below method. But it doesn't work. Can anyone help me?
$query = $this->getEntityManager()->createQuery(
'SELECT COUNT(a.idAction) AS nmbreAction , week(a.dateOuverture) AS week,( SELECT COUNT(c.idAction) , week(c.dateOuverture) FROM ActionActionBundle:Action c
WHERE c.cloture = 0 ) AS nmbreRetard FROM ActionActionBundle:Action a
GROUP BY week');
Mmm, you question lacks a lot of information. Is this what you need?
SELECT COUNT(a.idAction) AS nmbreAction ,
week(a.dateOuverture) AS week,
(SELECT COUNT(c.idAction)
FROM ActionActionBundle:Action c
WHERE c.cloture = 0
and week(c.dateOuverture) = week(a.dateOuverture)) AS nmbreRetard
FROM ActionActionBundle:Action a
GROUP BY week(a.dateOuverture)
You can't select more than 1 column in a sub query\correlated query in the select list, which was probably showed to you in the error message.
EDIT: Better of do that:
SELECT COUNT(a.idAction) AS nmbreAction ,
week(a.dateOuverture) AS week,
COUNT(CASE WHEN a.cloture = 0 THEN 1 END) as nmbreRetard
FROM ActionActionBundle:Action a
GROUP BY week(a.dateOuverture)

SQL code: adding value to one code but shown in other code as well

could somebody help me with this, please? I was checking answers around the net but still not successful.
I have two codes, code #1:
SELECT subject_note,ticket_id,created_time,status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket WHERE ticket_type = 1 AND status =0 AND team_type = 1 AND MONTH(FROM_UNIXTIME(closed_date)) = MONTH(NOW())
and YEAR(FROM_UNIXTIME(closed_date)) = YEAR(NOW())
AND
(
-- ASH
owner_id = 812400897
or owner_id = 1392249056
or owner_id = 739243661
or owner_id = 100002941128738
or owner_id = 619251675
or owner_id = 502392893
)
and code #2:
SELECT
subject_note,
cyborg_verify_tries,
ticket_id,
closed_date,
created_time,
status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket
WHERE ticket_type = 1
AND status =0
AND team_type = 1
and (FROM_UNIXTIME(closed_date)) >= DATE_SUB(now(), INTERVAL 6 MONTH)
AND
(
-- ASH
owner_id = 812400897
or owner_id = 1392249056
or owner_id = 739243661
or owner_id = 100002941128738
or owner_id = 619251675
or owner_id = 502392893
)
Both of these codes creating table and giving me the results what is good.
Problem what I have in here is I have to add manually every NEW "owner_id" into each code.
Is there any way how I could add NEW "owner_id" only into any code and second would be updated automatically? Both info are taken from the same table "sort_ticket".
Thank you for all the help.
You can use an extra table, where you put in the user id's and replace the fixed values with a select on this data:
SELECT
subject_note,
cyborg_verify_tries,
ticket_id,
closed_date,
created_time,
status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket
WHERE ticket_type = 1
AND status =0
AND team_type = 1
and (FROM_UNIXTIME(closed_date)) >= DATE_SUB(now(), INTERVAL 6 MONTH)
AND
(
-- ASH
select owner_id from newtable
)
same in the other select
You can use an additional table or an additonal view. Use a join to the new table/view in your queries and add new owner_id with an insert in the table or an UNION in the view.
To solve your proble with a view you can do this:
CREATE VIEW v_sort_ticket_owner AS
SELECT 812400897 as owner_id
UNION
SELECT 1392249056 as owner_id
UNION
SELECT 739243661 as owner_id
UNION
SELECT 100002941128738 as owner_id
UNION
SELECT 619251675 as owner_id
UNION
SELECT 502392893 as owner_id
--UNION
--SELECT newnumber as ownder_id
SELECT subject_note,ticket_id,created_time,status,
UPPER(SUBSTRING(datacenter,1,3)) region
FROM sort_ticket st
JOIN v_sort_ticket_owner sto
ON st.owner_id = sto.owner_id
WHERE st.ticket_type = 1 AND st.status =0 AND st.team_type = 1 AND
MONTH(FROM_UNIXTIME(st.closed_date)) = MONTH(NOW())
and YEAR(FROM_UNIXTIME(st.closed_date)) = YEAR(NOW())

SSRS create Age range

I'm trying to make a report that will display how many patients came in during a specific time frame for an age range. This is what I got so far, but the numbers its outputting are wrong, so I'm not sure what I missed. I've followed a couple of examples on here, but none have worked so far. Not sure if its cause I'm Joining to a different table or what.
select COUNT (DISTINCT MPFILE.PATIENT_NO) as 'Male 0-4'
from ENHFILE
Join MPFILE
on MPFILE.PATIENT_NO = ENHFILE.PATIENT_NO
where ENHFILE.COSITE = '300'
and ENHFILE.VISIT_PURPOSE = '2'
and MPFILE.SEX = 'M'
and (DATEDIFF(hour,MPFILE.DOB,GETDATE())/8766) > 5
and ENHFILE.ENCOUNTER_DATE between (#StartDate) and (#EndDate)
select COUNT (DISTINCT MPFILE.PATIENT_NO) as 'FeMale 0-4'
from ENHFILE
Join MPFILE
on MPFILE.PATIENT_NO = ENHFILE.PATIENT_NO
where ENHFILE.COSITE = '300'
and ENHFILE.VISIT_PURPOSE = '2'
and MPFILE.SEX = 'F'
and (DATEDIFF(hour,MPFILE.DOB,GETDATE())/8766) > 5
and ENHFILE.ENCOUNTER_DATE between (#StartDate) and (#EndDate)
Here is something that should get you what you want.
--First i just created some test data
if object_id('tempdb..#temp') is not null drop table #temp
select '8/15/1995' as DOB into #temp union all --Note this person is 21
select '8/16/1995' union all --Note this person is 21 TODAY
select '8/17/1995' union all --Note this person is 21 TOMORROW
select '4/11/1996' union all
select '5/15/1997' union all
select '9/7/2001'
--set the years old you want to use here. Create another variable if you need to use ranges
declare #yearsOld int
set #yearsOld = 21
select
convert(date,DOB) as DOB,
--This figures out how old they are by seeing if they have had a birthday
--this year and calculating accordingly. It is what is used in the filter
--I only put it here so you can see the results
CASE
WHEN CONVERT(DATE, CONVERT(VARCHAR(4), YEAR(GetDate()))+ '-'+ CONVERT(VARCHAR(2),MONTH(DOB)) + '-' + CONVERT(VARCHAR(2),DAY(DOB))) <= GETDATE() THEN DATEDIFF(yy,DOB,GETDATE())
ELSE DATEDIFF(yy,DOB,GETDATE()) -1
END AS YearsOld
from #temp
where
--here is your filter. Feel free to change the >= to what ever you want, or combine it to make it a range.
CASE
WHEN CONVERT(DATE, CONVERT(VARCHAR(4), YEAR(GetDate()))+ '-'+ CONVERT(VARCHAR(2),MONTH(DOB)) + '-' + CONVERT(VARCHAR(2),DAY(DOB))) <= GETDATE() THEN DATEDIFF(yy,DOB,GETDATE())
ELSE DATEDIFF(yy,DOB,GETDATE()) -1
END >= #yearsOld
EDIT
This is your method which doesn't account for if they have had a birthday this year. I use some test data. Notice the person born on 8/18/1995. They turn 21 tomorrow but using (DATEDIFF(hour,DOB,GETDATE())/8766) >= #yearsOld includes them when it shouldn't...
--First i just created some test data
if object_id('tempdb..#temp') is not null drop table #temp
select '8/15/1995' as DOB into #temp union all --Note this person is 21
select '8/16/1995' union all --Note this person is 21 TODAY
select '8/18/1995' union all --Note this person is 21 TOMORROW
select '4/11/1996' union all
select '5/15/1997' union all
select '9/7/2001'
--set the years old you want to use here. Create another variable if you need to use ranges
declare #yearsOld int
set #yearsOld = 21
select
convert(date,DOB) as DOB,
--This figures out how old they are by seeing if they have had a birthday
--this year and calculating accordingly. It is what is used in the filter
--I only put it here so you can see the results
CASE
WHEN CONVERT(DATE, CONVERT(VARCHAR(4), YEAR(GetDate()))+ '-'+ CONVERT(VARCHAR(2),MONTH(DOB)) + '-' + CONVERT(VARCHAR(2),DAY(DOB))) <= GETDATE() THEN DATEDIFF(yy,DOB,GETDATE())
ELSE DATEDIFF(yy,DOB,GETDATE()) -1
END AS YearsOld
from #temp
where
--here is your filter. Feel free to change the >= to what ever you want, or combine it to make it a range.
(DATEDIFF(hour,DOB,GETDATE())/8766) >= #yearsOld
RESULTS
DOB | YearsOld
1995-08-15 | 21
1995-08-16 | 21
1995-08-18 | 20 --this shouldn't be here...

Unrolling periodical events in MySQL

I've got a database with two tables, that I want to combine. One of the tables contains "incidental events", which just occur once. Next to this, I also have "periodical events". Now I want to combine these two in a view.
The incidental one simply has two columns, one called changes, the other one called date. The periodical one has three columns, changes, startDate and endDate. The difference between these two can be a maximum of 50 years, so manually typing out one case for every day is not going to work. Both views also have an AI ID. In this view I want to have a column date and a column changes.
To achieve this I want to unroll the periodical changes table, so that it shows one entry for every day in between the startDate and endDate. For instance:
incidental changes:
date | change
09/08/2015 | 5
11/08/2015 | 10
periodical changes:
startDate | endDate | change
09/08/2015 | 12/08/2015 | 7
These two I want combined into:
changes view:
date | change
09/08/2015 | 5
09/08/2015 | 7
10/08/2015 | 7
11/08/2015 | 10
11/08/2015 | 7
12/08/2015 | 7
My idea is to use something like this:
SELECT * FROM incidental_changes,(
SET #id = (SELECT min(ID) AS min FROM periodical_changes WHERE 1)
SET #maxID = (SELECT max(ID) AS max FROM periodical_changes WHERE 1)
WHILE (#id <= #maxID) DO
SET #firstDate = (SELECT startDate FROM periodical_changes WHERE id = #id)
SET #lastDate = (SELECT endDate FROM periodical_changes WHERE id = #id)
WHILE (#firstDate <= #lastDate) DO
SELECT #firstDate AS date, change FROM periodical_changes WHERE id = #id
#firstDate = #firstDate + INTERVAL 1 DAY
END
#id = #id + 1
END
) WHERE 1
This gives me an error,
CREATE ALGORITHM = UNDEFINED VIEW all_periodicals AS SELECT * FROM
incidental_changes,( SET #id = (SELECT min(ID) AS min FROM
periodical_changes WHERE 1) SET #maxID = (SELECT max(ID) AS max FROM
periodical_changes WHERE 1) WHILE (#id <= #maxID) DO SET #firstDate =
(SELECT startDate FROM periodical_changes WHERE id = #id) SET
#lastDate = (SELECT endDate FROM periodical_changes WHERE id = #id)
WHILE (#firstDate <= #lastDate) DO SELECT #firstDate AS date, change
FROM periodical_changes WHERE id = #id #firstDate = #firstDate +
INTERVAL 1 DAY END #id = #id + 1 END ) WHERE 1
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near 'SET #id = (SELECT min(ID) AS min FROM periodical_changes WHERE
1) SET #' at line 5
and I'm guessing that if I'd manage to fix this error there'd be more. So, is there any way to do this the way I want, or do I have to look for a different approach?
EDIT:
Okay, so far I have not found a way to do this in a view or so. So instead I am now using a routine. This routine has one parameter, account INT. The definition I am using so far is as followed:
BEGIN
DECLARE periodicalID int;
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE periodicalCursor CURSOR
FOR SELECT periodicals.periodicalID FROM periodicals WHERE periodicals.accountID = account;
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET v_finished = 1;
CREATE TEMPORARY TABLE results LIKE incidentials;
ALTER TABLE results DROP INDEX date;
SET #periodicalID = -1;
OPEN periodicalCursor;
allPeriodicals: LOOP
FETCH periodicalCursor INTO periodicalID;
IF (v_finished) THEN
LEAVE allPeriodicals;
END IF;
SELECT periodicals.startDate,periodicals.numberOfPeriods,periodicals.period,periodicals.endDate,periodicals.money FROM periodicals WHERE periodicals.periodicalID = periodicalID AND periodicals.accountID = account INTO #startDate, #numberOfPeriods, #period,#endDate,#money;
SET #intervalStatement = "SELECT ? + INTERVAL ? ";
SET #intervalStatement = CONCAT(#intervalStatement,#period," INTO #res");
PREPARE intervalStatement FROM #intervalStatement;
WHILE #startDate <= #endDate DO
EXECUTE intervalStatement USING #startDate,#numberOfPeriods;
SET #startDate = #res;
INSERT INTO results(accountID,date,money) VALUES (account,#startDate,#money);
END WHILE;
END LOOP allPeriodicals;
INSERT INTO results(accountID,date,money) SELECT accountID,date, money FROM incidentials WHERE incidentials.accountID = account;
SELECT * FROM results ORDER BY date;
END
This poses the problem of performance though. With only one periodical entry spread over a year this query already takes about 16 seconds. So even though this approach works, I either did something wrong causing it to take this long or this is not the right way to go.
Let me presume you have a numbers table. Then you can do:
select i.date, i.change
from incidental
union all
select date_add(p.startDate, interval n.n - 1 day), p.change
from periodic p join
numbers n
on date_add(p.startDate, interval n.n - 1 day) <= p.endDate;
For a select query, you can generate the numbers using a subquery, if you know the maximum length. Something like:
select i.date, i.change
from incidental
union all
select date_add(p.startDate, interval n.n - 1 day), p.change
from periodic p join
(select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5 union all select 6 union all select 7
) n
on date_add(p.startDate, interval n.n - 1 day) <= p.endDate;
This doesn't work in a view, however. For that, you really do need a numbers table.

MYSQL CASE/IF over a value selected with SELECT

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