I have some data which I am trying to align as one row instead of two.
Example what I am getting
Name Feb Mar
Tom $229.32 NULL
Tom NULL $182.63
How I need is below
Name Feb Mar
Tom $229.32 $182.63
Below is the query which I am using
select Name,
case
when convert(varchar(7), bill_dt, 126) = '2018-02'
then sum(cast(amount as float))
end Feb,
case
when convert(varchar(7), bill_dt, 126) = '2018-03'
then sum(cast(amount as float))
end Mar
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01'
group by Name, bill_dt
Use conditional aggregation:
select Name,
SUM( case when convert(varchar(7), bill_dt, 126) = '2018-02'
then cast(amount as float)
else 0
end) as Feb,
SUM( case when convert(varchar(7), bill_dt, 126) = '2018-03'
then cast(amount as float)
else 0
end) as Mar
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01'
group by Name
For your dataset, use a query that "reduces" the billing date to the first of the month (to give the report something to group by), for example:
select
Name,
DATEADD(month, DATEDIFF(month, 0, bill_dt), 0) AS bill_mnth,
amount
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01';
You do not have to group yet, you can let the report do this for you. And don't use anything that sounds sophisticated and starts with "conditional", unless you want to use your report only for Febuary and March 2018.
Add a matrix to the report and use the field selector to select
Name for Rows
bill_mnth for Columns and
amount for Data
This will create a Row group grouped by Name and a Column group grouped by bill_mnth. In order to display the 3-letter abbreviation of the month instead of a date, right-click the TextBox and change the expression of that column header to
=Format(Fields!bill_mnth.Value, "MMM")
... or even "MMM yyyy" if you plan to enlarge the interval. And of course, format the data cell as desired.
Related
I am using sql to write up a query in which I am trying to choose records that have their date_from column (of type date/time) that satisfy these conditions:
it can be any year
months are june, july, august and september
AND IF IT IS JUNE, IT SHOULD CONSIDER FROM THE 15th JUNE ONWARDS
Here's what i've tried ..
Select name, surname
FROM employees emp
where month(emp.date_from) IN ('06' , '07' , '08', '09')
I have also tried using CASE but failed. Any help please?
WHERE MONTH(emp.date_from) IN (7,8,9)
OR (MONTH(emp.date_from) = 6 AND DAY(emp.date_from) >= 15);
UPDATE
Or as dates are treated as strings in MySQL
WHERE RIGHT(emp.date_from, 5) BETWEEN '06-15' AND '09-30';
I don't know which would perform better however.
Sqlserver 2012
SELECT
*
FROM
employees
WHERE
DateFromParts(2000,month(date_from),day(date_from))
between '2000-06-15' and '2000-09-30'
Year 2000 is chosen because it is leap year and will handle leap year issues around 2000-02-29.
SELECT firstname,
lastname,
dateofbirth
FROM patient
WHERE Day(dateofbirth) >= CASE
WHEN Month(dateofbirth) = '06' THEN 15
END
OR Month(dateofbirth) IN ( '07', '08', '09' )
ORDER BY Month(dateofbirth)
I have a table (myItems) with an item "id" and "date". Now i want to read out, how many items there are per month (i also want to distinguish between October 2013 and October 2014).
I started with:
SELECT Count(okt.id) AS Oktober, Count(nov.id) AS November
FROM `myItems` as okt,
`myItems` as nov
WHERE (okt.date between '2013-10-01' and '2013-10-31')
OR (nov.date between '2013-11-01' and '2013-11-30')
But it prints out a ridiculously large number. What am i doing wrong?
Try this. This will divide data into months and then do the COUNT :
SELECT SUM(CASE WHEN MONTH(date) = 10 THEN 1 ELSE 0 END) AS Oktober
, SUM(CASE WHEN MONTH(date) = 11 THEN 1 ELSE 0 END) AS November
FROM `myItems`
Demo: SQL Fiddle
With YEAR integrated:
SELECT 2013 as Year
, SUM(CASE WHEN MONTH(date) = 10 THEN 1 ELSE 0 END) AS Oktober
, SUM(CASE WHEN MONTH(date) = 11 THEN 1 ELSE 0 END) AS November
FROM `myItems`
WHERE YEAR(date) = 2013
UNION ALL
SELECT 2014 as Year
, SUM(CASE WHEN MONTH(date) = 10 THEN 1 ELSE 0 END) AS Oktober
, SUM(CASE WHEN MONTH(date) = 11 THEN 1 ELSE 0 END) AS November
FROM `myItems`
WHERE YEAR(date) = 2014;
;
Demo: Fiddle
With inspiration from #user77318
SELECT YEAR(date) as Year, month(date) as month, count(id) as count
FROM myItems
GROUP BY YEAR(date), MONTH(date);
I personally recommend this, more beautiful. Then you can do all the presentation stuffs on Application Layer.
Try this. Group the result by month:
SELECT month(date) as month, count(id) as count FROM myItems WHERE date between '2013-10-01' and '2013-11-30' GROUP BY MONTH(date);
Example of output result:
Month | Count
10 | 100
11 | 200
Probably you are not using join, you are just giving the conditions. First try to join these 2 tables with the primary keys or with some unique and common data column. Then try to execute above query. Somthiong like this:-
SELECT Count(okt.id) AS Oktober, Count(nov.id) AS November
FROM `myItems` as okt,
`myItems` as nov
WHERE okt.id = nov.id
AND (okt.date between '2013-10-01' and '2013-10-31')
OR (nov.date between '2013-11-01' and '2013-11-30');
May be this is helpful for you.
I have a MySQL DB as such:
Date Customer_ID
How can I turn it into:
Customer_ID | Count_Visits_Past_Week | Count_Visits_Past_Month | Count_Visits_Past_90days | Count_Total
Note : Count_Total =sum of the other three counts
Thanks
The first step is to determine the demarcation points for the specified date ranges.
There's several questions to answer here: did you want to compare just the DATE ('yyyy-mm-dd') and disregard any time component?
By "past week", does that mean within the last seven days, or does it mean so far since the previous Sunday, or does it mean the last last full week, from Sunday through Saturday.
For "past month", does that mean the previous whole month, from the first through the end of the month? Or does it mean that if the query is run on the 20th of the month, we want dates since the 20th of the previous month up until today? Or yesterday?
Once we know the points in time that begin and end each specified period, relative to today's date, we can build expressions that evaluate to those dates.
For example, "past week" could be represented as the most recent seven day period:
DATE(NOW())-INTERVAL 1 WEEK -thru- DATE(NOW())
And "past month" can be represented as the same "day of month" (e.g. 17th) of the immediately preceding month up until today:
DATE(NOW())-INTERVAL 1 MONTH -thru- DATE(NOW())
That's really the first step, to determine the begin and end dates of each specified period.
Once we have that, we can move on to building a query that gets a "count" of rows with a date column that falls within each period.
The "trick" is to use conditional tests in expressions in the SELECT list of the query. We'll use those conditional tests to return a 1 if the row is to be included in the "count", and return 0 or NULL if the row should be excluded.
I prefer to use the SUM() aggregate function to get the "count". But it's also possible to use COUNT() aggregate. (If we use COUNT(), we need to use an expression that returns NULL when the row is to be excluded. I prefer to return a 1 or 0; I think it makes debugging easier.
Here's an outline of what a "count" query would look like.
SELECT t.Customer_Id
, SUM(IF( <some_condition> ,1,0) AS Count_something
, SUM(IF( <other_condition> ,1,0) AS Count_something_else
FROM mytable t
GROUP BY t.Customer_Id
When <some_condition> is true, we return a 1, otherwise we return 0.
To test the conditional expressions, it's often easiest to avoid doing the aggregation, and just return the individual rows:
That way, we can see which individual rows are going to be included in each "count".
For example:
SELECT t.Customer_ID
, t.date
, IF(t.date BETWEEN DATE(NOW())-INTERVAL 1 WEEK AND DATE(NOW()),1,0)
AS visit_past_week
, IF(t.date BETWEEN DATE(NOW())-INTERVAL 1 MONTH AND DATE(NOW()),1,0)
AS visit_past_month
FROM mytable t
ORDER BY t.date, t.Customer_Id
That query doesn't return the "count", it just returns the results of the expressions, which can be useful in testing. And of course we want to test the expressions that return the beginning and ending date of each period:
SELECT DATE(NOW()) - INTERVAL 1 WEEK AS past_week_begin
, DATE(NOW()) AS past_week_end
With this approach, the same row can be included in multiple "counts" with one query and one pass through the table.
Note that the expressions inside the SUM() aggregate in the query below are taking advantage of a convenient shorthand, an expression evaluated as a boolean will return 1 if TRUE, 0 if false, or a NULL.
To use the COUNT aggregate, we need to insure that the expression being aggregated returns a non-NULL when the row is to be "counted", and a NULL when the row is to be excluded from the count. So we use the convenient NULLIF function to return NULL if the value returned by the expression is a zero.
SELECT t.Customer_ID
, COUNT(NULLIF( t.date BETWEEN DATE(NOW())-INTERVAL 1 WEEK AND DATE(NOW()),0))
AS Count_Visits_Past_Week
, COUNT(NULLIF( t.date BETWEEN DATE(NOW())-INTERVAL 1 MONTH AND DATE(NOW()),0))
AS Count_Visits_Past_Month
, COUNT(NULLIF( t.date BETWEEN DATE(NOW())-INTERVAL 90 DAY AND DATE(NOW()),0))
AS Count_Visits_Past_90days
, COUNT(NULLIF( t.date BETWEEN DATE(NOW())-INTERVAL 1 WEEK AND DATE(NOW()),0))
+ COUNT(NULLIF( t.date BETWEEN DATE(NOW())-INTERVAL 1 MONTH AND DATE(NOW()),0))
+ COUNT(NULLIF( t.date BETWEEN DATE(NOW())-INTERVAL 90 DAY AND DATE(NOW()),0))
AS Count_Total
FROM mytable t
GROUP BY t.Customer_Id
NOTE: NULLIF(a,b) is a convenient shorthand for IF a IS NULL THEN return b ELSE return a
Returning the Count_Total is a bit odd, since it's got the potential to "count" the same row multiple times... but the value it returns should match the total of the individual counts.
I think this will give you what you want.
select customer_id,
sum(case when splitter = 'week' then num_visits else 0 end) as visits_this_week,
sum(case when splitter = 'month' then num_visits else 0 end) as visits_this_month,
sum(case when splitter = '90days' then num_visits else 0 end) as visits_last_90days,
sum(num_visits) as total
from (select customer_id, 'week' as splitter, count(*) as num_visits
from tbl
where extract(week from date) = extract(week from sysdate())
and extract(year from date) = extract(year from sysdate())
group by customer_id
union all
select customer_id, 'month' as splitter, count(*) as num_visits
from tbl
where extract(month from date) = extract(month from sysdate())
and extract(year from date) = extract(year from sysdate())
group by customer_id
union all
select customer_id, '90days' as splitter, count(*) as num_visits
from tbl
where date between date_sub(sysdate(), interval 90 day) and
sysdate()) x
group by customer_id
sql fiddle example: http://sqlfiddle.com/#!2/a762c/12/0
I have created this mysql code to count at only specific date range, i dumped the output of my mysql code and here it is:
SELECT COUNT(
IF(
DATE(q.date_emailed) BETWEEN '2014-02-01' AND '2014-02-28',
1,
0
)
) AS 'Feb',
COUNT(
IF(
DATE(q.date_emailed) BETWEEN '2014-03-01' AND '2014-03-31',
1,
0
)
) AS 'March',
COUNT(
IF(
DATE(q.date_emailed) BETWEEN '2014-01-01' AND '2014-01-31',
1,
0
)
) AS 'Jan'
FROM
database.quotes q
WHERE (DATE(q.date_emailed) BETWEEN '2014-01-01' AND '2014-03-31')
But this outputs same count for each month, in which i confirmed that february and march has zero counts. What am I missing here?
COUNT() counts non-null values. You can fix your code by using sum() instead. You can also simplify it by removing the if statements:
SELECT SUM(DATE(q.date_emailed) BETWEEN '2014-02-01' AND '2014-02-28') AS Feb,
SUM(DATE(q.date_emailed) BETWEEN '2014-03-01' AND '2014-03-31') AS March,
SUM(DATE(q.date_emailed) BETWEEN '2014-01-01' AND '2014-01-31') AS Jan
FROM database.quotes q
WHERE DATE(q.date_emailed) BETWEEN '2014-01-01' AND '2014-03-31';
In MySQL, a boolean result is treated as 0 for "false" and 1 for "true". This is a great convenience and allows you to use sum() to count the number of matches.
Note that I also removed the single quotes around the column names. Single quotes should be used for string and date constants, not for identifiers.
EDIT:
You can have this query run faster by using an index on q.date_emailed. However, I don't think the index will be used because of the date() function. You can fix this by changing the logic:
SELECT SUM(DATE(q.date_emailed) BETWEEN '2014-02-01' AND '2014-02-28') AS Feb,
SUM(DATE(q.date_emailed) BETWEEN '2014-03-01' AND '2014-03-31') AS March,
SUM(DATE(q.date_emailed) BETWEEN '2014-01-01' AND '2014-01-31') AS Jan
FROM database.quotes q
WHERE q.date_emailed >= '2014-01-01' AND
q.date_emailed < '2014-04-01';
You should use SUM instead of COUNT if you want to SUM up the 0 and 1.
The COUNT will COUNT the number of row, the SUM will sum up the values.
This is a follow-up question on Get age from the birthday field with type date using SQL. I have a date field in a MySQL database for the birthday of a user and get the age using this query:
SELECT
ROUND(DATEDIFF(
Cast((SELECT NOW()) as Date),
Cast(birthday as Date)
) / 365, 0) as age
FROM member
Now, I need to select the number of people in different age groups. For example, I need to know how many people are in the age group 13-17, 18-21, 22-25, 26-35, 36-50, 51-MAX.
Is that possible using MySQL?
I have thought of UNIONs, like this:
SELECT
ROUND(DATEDIFF(
Cast((SELECT NOW()) as Date),
Cast(birthday as Date)
) / 365, 0) as age,
1 as agegroup
FROM member WHERE age >=13 AND age <=17
UNION
SELECT
ROUND(DATEDIFF(
Cast((SELECT NOW()) as Date),
Cast(birthday as Date)
) / 365, 0) as age
2 as agegroup
FROM member WHERE age >=18 AND age <=21
But that would be long and ugly. There must be a better way!
select AgeGroup
, count(*)
from (
select case
when age between 13 and 17 then 1
when age between 18 and 21 then 2
...
end as AgeGroup
from (
SELECT ROUND(DATEDIFF(Cast(NOW() as Date),
Cast(birthday as Date)) / 365, 0) as age
FROM YourTable
) as SubQueryAlias
) as SubQueryAlias2
group by
AgeGroup
Another possible solution:-
SELECT AgeRange.MinAge, AgeRange.MaxAge, COUNT(*)
FROM
(
SELECT 13 AS MinAge, 17 AS MaxAge
UNION SELECT 18, 21
UNION SELECT 22, 25
UNION SELECT 26, 35
UNION SELECT 36, 50
UNION SELECT 51, 9999
) AgeRange
INNER JOIN YourTable
ON ROUND(DATEDIFF(CAST(NOW() as DATE), CAST(birthday as DATE)) / 365, 0) BETWEEN AgeRange.MinAge AND AgeRange.MaxAge
GROUP BY AgeRange.MinAge, AgeRange.MaxAge
Possibly easier to expand if needs be, or to move to using date ranges from a table (so the resulting report could be updated by users easily if required).
If you had the age as a column in a table you would do it like this:
SELECT
SUM(CASE WHEN age < 10 THEN 1 ELSE 0 END) AS under10,
SUM(CASE WHEN 10<age AND age <19 THEN 1 ELSE 0 END) AS age10to19,
.
.
.
FROM table
There are likely to be minor changes because age isn't in its own column or if you want extra or different ranges. I'm sure you can work them out yourself!