printing quantity of sales per page not overall quantity of sales - javascript

So Iam making a birt report on enclipse my goal is to output on each page amount of sales of a given person, not overall amount of sales of that person.
Consider this table(consider we only have 1 person):
personID sales date
------- ----- -----
111 10 2010-02-02
111 15 2010-02-03
111 5 2010-03-03
111 7 2010-04-03
111 8 2011-01-01
111 9 2013-01-01
111 20 2014-01-01
111 25 2014-03-02
The scenario on each page:
It shows 3 results(which I want)
but below each page its showing 99 sales (which I don't want)
What I want is that:
on 1st page it shows 30 sales (for 3 rows)
on 2nd page it shows 24 sales(for 3 rows)
and last page it shows 45(for 2 remaining rows)
what I did is that (i dont know if its right approach):
DENSE_RANK() OVER (ORDER BY sales) AS Row,
convert(integer,ROW_NUMBER() over(order by sales)/4) as page
which turned my table into
personID sales date Row page
------- ----- ----- ---- ----
111 10 2010-02-02 1 0
111 15 2010-02-03 2 0
111 5 2010-03-03 3 0
111 7 2010-04-03 4 1
111 8 2011-01-01 5 1
111 9 2013-01-01 6 1
111 20 2014-01-01 7 1
111 25 2014-03-02 8 2
As you can see there's another issue which is:
the 1st 3 rows got page(0)
but row 4-5-6-7 got page 1 which is wrong it should have been row 4-5-6 page 1
and row 7-8 page 2
I am also working on eclipse using JavaScript
<method name="onPageEnd"><![CDATA[var sales = this.getInstancesByElementName("sales");
var tmp=0;
if( sales != null )
{
for(var i=0; i< sales.length; i++ )
{
for(var j=0;j<3;j++)
{
//Instance of DataItemInstance
var sales = sales[i];
tmp+=parseInt(sales.getValue());
}
}
}

Once your query results are correct, you should compute SUM(sales) based on the page.
This can be done either with SQL (Oracle SQL syntax)
with x as
(
your_query_here
)
select x.*,
sum(sales) over (partition by page) -- IIRC
from x
or with BIRT, if you create a GROUP (called "page" for example) in your (layout) table, and an aggregate column binding based on this group.
Now to the query itself:
I don't think that the DB actually shows the results you state with your query.
Probably "Row" is defined in your query as
DENSE_RANK() OVER (ORDER BY "date" AS "Row"
I often use something like this for "matrix reports in SQL" and the like (asssuming you want 3 rows/page). This is a puire SQL solution:
with
y as (
select ...,
ROW_NUMBER() over(order by "sales") partition by ("personID") - 1 as "Row"
-- Note: Row is zero-based: 0,1,2,...
),
x as (
select y.*,
MOD(y."Row", 3) + 1 as "RowOnPage"
trunc(y."Row"/3) + 1 as "Page"
from y
)
select x.*,
sum("sales") over (partition by "personId", "Page") as SumSalesPerPersonAndPage
-- IIRC
from x
This is probably not quite correct (because I don't know how you intend to handle the different persons), but you get the idea...
For creating reports, it is a great advantage to know analytic functions.
I usually test my queries outside of BIRT (eg with SQL*Developer).

Related

pagination with dots in React using Javascript

I am building pagination where I want to display '...' at certain points. The amount of pages is dictated by user selection; there are 650-ish posts, and users can choose to display 15, 25, 50, or 100 items at a time. Anyway, let's say that there are 45 pages.
If I am on page one, I want it to look like this:
1 2 3 ... 45
if I am on page 3, I want it to look like this:
1 ... 2 3 4 ... 45
if I am on page 44 (or 45), I want it to look like this:
1... 43 44 45
I am doing this all with JS, I'm not using any extra pagination packages from React. Currently, I have some functionality but I am getting stumped on how to adjust my for loop.
So, right now, if I am on page 1, it looks like :
1 2 ... 43 44 45
If I'm on page 3 :
1 2 3 4 ... 43 44 45
If I am on page 4:
1... 3 4 5 ... 43 44 45
**If I am on page 45:
1 ... 44 45
I looked around for a long time, and finally found a stackoverflow thread that helped. I implemented the basic while loop provided by derpirscher.
let pagination = [], i = 1;
while (i <= totalPageCount) {
if (i <= 1 ||
i >= totalPageCount - 2||
i >= currentPage - 1 && i <= currentPage + 1) {
pagination.push(i);
i++;
} else {
pagination.push('...');
//jump to the next page to be linked in the navigation
i = i < currentPage ? currentPage - 1 : totalPageCount - 2;
}
}
In this example, totalPageCount is how many pages there are total, and currentPage is the page the user is currently on. I tried to incorporate some sibling logic where if, for example, the left sibling index was greater than two, I inserted dots. That just resulted in there being dots on the left side of just about every page number, and I definitely didn't want that.
If it is important, I map through pagination directly in my render function to generate the template.
{pagination.map((pageNumber) => {
return (
<li key={pageNumber}>
<button
onClick={() => onPageChange(pageNumber)}
>
{pageNumber}
</button>
</li>
)
})}
Any thoughts or useful resources on this would be appreciated. I know my JS could be better, which is partly why I am trying to practice doing it this way!

Why is my function for google sheets returning TypeError: given_list is not iterable? Or: How can I input an array into a google sheets function?

I'm making a custom function in google sheets which counts the number of occurrences of all items in a given array in a given range of cells.
The way I'm given to understand google sheets functions work are that the range you give is turned into a two-dimensional array of the items in the cells. So range A4:B5 would be transmitted to the function as
[[the contents of A4, the contents of B4],
[the contents of A5, the contents of B5]
The next input is a list of the items to check for in those cells. From what I could find online, arrays are given in google sheets by using brackets like these {}. the function I created is given below. I have never used javascript before but I know other languages and I just googled how to use for loops and if statements to create the function, so I'm certain the error is due to something simple that I don't know about or missed.
function count_if_in_set(range, given_list) {
let counter = 0;
for (dim_1 of range) {
for (dim_2 of dim_1) {
for (item of given_list) {
if (item == dim_2) {
counter += 1
}
}
}
}
return counter
}
When I try to use this function in google sheets with the following input: =count_if_in_set(Z30:Z33, {1}), I receive the following error: TypeError: given_list is not iterable (line 5).
The contents of cells Z30 to Z33 are the integers 1, 2, 3, 3 which should be given to the function as the following 2-dimensional array: [[1], [2], [3], [3]]
The problem is that the list [1] is not iterable. I have 2 hypotheses as to why this is:
I coded something wrong because I'm very new to Javascript
The input {1} is not transmitted to a list when google sheets gives it to the function
To check if it was the former, I went through all the aspects of my function. I first checked if you have to declare the type of variable it was when you created the function, but according to what I saw when I googled it you don't. I then changed all my for (a of b) to for (let a of b) but that did nothing to help, and after that I was stuck.
To try and solve it in the case it was a problem with giving the code an array, I tried changing my input from =count_if_in_set(Z30:Z33, {1}) to =count_if_in_set(Z30:Z33, [1]), but that threw up a formula parse error so I knew that wasn't it, and I tried changing the input to =count_if_in_set(Z30:Z33, (1)) but that returned the same error. And after that I was stuck and had no more ideas.
You can get the same result with a plain vanilla spreadsheet formula, like this:
=arrayformula( countif(Z30:Z43, { 1, 2, 3 }) )
To get just the grand total, use this:
=arrayformula( sum( countif(Z30:Z43, { 1, 2, 3 }) ) )
To count how many cells have a text string that contains one of the search keys, use this:
=arrayformula( sum( countif( Z30:Z43, "*" & { "a", "b" } & "*" ) ) )
If you need to use a custom function for some reason, try something this to get started:
function count_if_in_set(values, given_list) {
let counter = 0;
values.map(row => row.map(value =>
counter += (given_list.indexOf(value) !== -1)
));
return counter;
}
This is really an anti-pattern, because the map result is not used for anything. People would tend to use Array.reduce(), but the map-map pattern may be easier to follow, and it is the one typically employed in custom functions that most often do not aggregate the result but return exactly one value per argument value.
Some of the best resources for learning Google Apps Script include the Beginner's Guide, the New Apps Script Editor guide, the Fundamentals of Apps Script with Google Sheets codelab, the Extending Google Sheets page, javascript.info, Mozilla Developer Network and Apps Script at Stack Overflow.
Try this:
Just looking for the number of 1,2,3,4,5,6,7,8 or 9 in the selected range and return the item and count
function checkforitems(a, b) {
let obj = {pA:[]};
Logger.log(a);
Logger.log(b);
let arr = b[0];//b enters as a 2d array with a single element
//collect counts with a pivot table
a.forEach(r => {
r.forEach(c => {
let index = arr.indexOf(c);
if(~index) {
if(!obj.hasOwnProperty(arr[index])) {
obj[arr[index]]=1;
obj.pA.push(arr[index]);//collect elements as an array
} else {
obj[arr[index]]+=1;
}
}
});
});
let l = '';
//obj.pA.sort((x,y) => x - y);//if searching for numbers you can use this to sort them before displaying them
obj.pA.forEach(e => {
l += `${e}-${obj[e]}\n`;
});
return l;
}
My Test Sheet:
COL1
COL2
COL3
COL4
COL5
COL6
COL7
COL8
COL9
COL10
1
17
8
10
2
7
4
19
12
11
8
13
7
1
6
14
8
19
15
1
17
15
15
6
7
3
3
17
8
12
8
2
17
9
9
7
15
16
19
11
14
11
19
0
15
4
16
11
1
11
1
3
3
19
3
1
5
4
3
16
10
8
8
2
17
18
0
1
17
6
1
0
10
18
12
16
11
4
7
13
10
18
6
12
12
5
3
11
9
5
13
2
2
8
5
4
8
12
18
2
0
18
18
18
17
4
6
14
8
8
1
11
12
1
15
17
18
3
0
6
19
5
17
11
12
9
12
1
6
15
12
5
7
1
14
9
4
4
18
12
3
1
11
8
11
9
17
6
12
5
11
12
16
5
5
5
6
12
3
5
16
0
18
14
8
4
16
0
10
0
15
13
4
17
14
10
9
9
2
4
13
12
11
15
12
18
0
8
19
19
3
1
0
3
1
16
18
6
1
2
My formula (L22):
=checkforitems(A2:J21,{1,2,3,4,5,6,7,8,9})
returned result:
1-16
8-14
2-8
7-6
4-11
6-10
3-12
9-8
5-11
Test Sheet With Results:
To anyone looking for a way to make that function work:
I did the same thing but changed it slightly so the second input was a range of cells which contained the range I wanted to search through

Automated meetings schedule planner

I work in an event organizing company, our main business is organizing “speed dating” meetings between buyers (retailers and distributors) and manufacturers of food and beverages. We have people that create a schedule for events and I would like to somehow automate this process.
I would ask for help with logic for a web app that would schedule the meetings.
There are 10 different companies on each side.
The meetings should be only if one side chose a company from the other side.
Each meeting is 15 minutes.
The whole event should we 2-2,5 hours long.
Any suggestions on how to create a great schedule automatically?
P.S. I am sorry if my question is not clear, this is my first Stack Overflow question.
I don't have a JavaScript solution, but this can be solved with mathematical optimization tools.
Let's start with some data:
---- 11 SET b buyers
buyer1 , buyer2 , buyer3 , buyer4 , buyer5 , buyer6 , buyer7 , buyer8 , buyer9 , buyer10
---- 11 SET s sellers
seller1 , seller2 , seller3 , seller4 , seller5 , seller6 , seller7 , seller8 , seller9
seller10
---- 11 SET r rounds
round1, round2, round3, round4, round5, round6, round7, round8
---- 11 PARAMETER wantMeeting a meeting has been requested
seller1 seller2 seller3 seller4 seller5 seller6 seller7 seller8 seller9
buyer1 1 1
buyer2 1 1
buyer3 1 1
buyer4 1 1
buyer5 1 1 1
buyer6 1 1 1
buyer7 1 1 1 1
buyer8 1 1
buyer9 1 1 1
buyer10 1 1
+ seller10
buyer8 1
Introduce binary variables:
x(b,s,r) = 1 if buyer b meets seller s in round r
0 otherwise
We only consider the cases where wantMeeting=1. Implicitly, when wantMeeting=0, we assume x(b,s,r)=0.
Constraints:
Meeting is requested:
sum(r, x(b,s,r)) = 1 for all b,s with wantMeeting(b,s)=1
Buyer can only have one meeting per round
sum(s|wantMeeting(b,s)=1, x(b,s,r)) <= 1 for all b,r
Seller can only have one meeting per round
sum(b|wantMeeting(b,s)=1, x(b,s,r)) <= 1 for all s,r
Here | is the mathematic notation for "such that".
I have also added some constraints, and an objective to minimize the number of rounds needed. The resulting Mixed Integer Programming model gives as result:
---- 42 VARIABLE x.L meetings
round1 round2 round3 round4
buyer1 .seller1 1
buyer1 .seller9 1
buyer2 .seller5 1
buyer2 .seller7 1
buyer3 .seller3 1
buyer3 .seller4 1
buyer4 .seller1 1
buyer4 .seller3 1
buyer5 .seller2 1
buyer5 .seller4 1
buyer5 .seller6 1
buyer6 .seller5 1
buyer6 .seller6 1
buyer6 .seller9 1
buyer7 .seller1 1
buyer7 .seller2 1
buyer7 .seller5 1
buyer7 .seller6 1
buyer8 .seller3 1
buyer8 .seller8 1
buyer8 .seller10 1
buyer9 .seller2 1
buyer9 .seller5 1
buyer9 .seller6 1
buyer10.seller7 1
buyer10.seller9 1
---- 42 VARIABLE round.L round is used
round1 1, round2 1, round3 1, round4 1
---- 42 VARIABLE numRounds.L = 4 number of rounds needed
I did not have a capacity per round (say n tables are available). This is not very difficult to add. More details are here.
For some more examples of these type of models see:
Scheduling Business Dinners
Speed Dating Scheduling
I probably would solve this on a server, but if you insist on a JavaScript solution, there is a JavaScript port of the GLPK Mixed Integer Programming Solver (link). You may also look into Constraint Programming Solvers (there are a few available in JavaScript).

Scraping Javascript-Rendered Content in R from a Webpage without Unique URL

I want to scrape historical results of South African LOTTO draws (especially Total Pool Size, Total Sales, etc.) from the South African National Lottery website. By default one sees links to results for the last ten draws, or one can select a date range to pull up a larger set of links to draws (which will still display only ten per page).
Hovering in the browser over a link e.g. 'LOTTO DRAW 2012' we see javascript:void(); so it is clear that the draw results will be rendered using Javascript. Reading advice on an R Web Scraping Cheat Sheet, I realized that I needed to open Google Chrome Developer tools, then open Network tab, and then click the link to the draw 'LOTTO DRAW 2012'. When I did so, I could see that this url is being called with an initiator
When I right-click on the initiator and select 'Copy Response', I can see the data I need inside a 'drawDetails' object in what appears to be JSON code.
{"code":200,"message":"OK","data":{"drawDetails":{"drawNumber":"2012","drawDate":"2020\/04\/11","nextDrawDate":"2020\/04\/15","ball1":"48","ball2":"6","ball3":"43","ball4":"41","ball5":"25","ball6":"45","bonusBall":"38","div1Winners":"1","div1Payout":"10546013.8","div2Winners":"0","div2Payout":"0","div3Winners":"28","div3Payout":"7676.4","div4Winners":"62","div4Payout":"2751.4","div5Winners":"1389","div5Payout":"206.3","div6Winners":"1872","div6Payout":"133","div7Winners":"28003","div7Payout":"50","div8Winners":"20651","div8Payout":"20","rolloverAmount":"0","rolloverNumber":"0","totalPrizePool":"13280236.5","totalSales":"11610950","estimatedJackpot":"2000000","guaranteedJackpot":"0","drawMachine":"RNG2","ballSet":"RNG","status":"published","winners":52006,"millionairs":1,"gpwinners":"52006","wcwinners":"0","ncwinners":"0","ecwinners":"0","mpwinners":"0","lpwinners":"0","fswinners":"0","kznwinners":"0","nwwinners":"0"},"totalWinnerRecord":{"lottoMillionairs":28716702,"lottoWinners":337285646,"ithubaMillionairs":135763,"ithubaWinners":305615802}},"videoData":[{"id":"1049","listid":"1","parentid":"1","videosource":"youtube","videoid":"chHfFxVi9QI","imageurl":"","title":"LOTTO, LOTTO PLUS 1 AND LOTTO PLUS 2 DRAW 2012 (11 APRIL 2020)","description":"","custom_imageurl":"","custom_title":"","custom_description":"","specialparams":"","lastupdate":"0000-00-00 00:00:00","allowupdates":"1","status":"0","isvideo":"1","link":"https:\/\/www.youtube.com\/watch?v=chHfFxVi9QI","ordering":"10001","publisheddate":"2020-04-11 20:06:17","duration":"182","rating_average":"0","rating_max":"0","rating_min":"0","rating_numRaters":"0","statistics_favoriteCount":"0","statistics_viewCount":"329","keywords":"","startsecond":"0","endsecond":"0","likes":"6","dislikes":"0","commentcount":"0","channel_username":"","channel_title":"","channel_subscribers":"9880","channel_subscribed":"0","channel_location":"","channel_commentcount":"0","channel_viewcount":"0","channel_videocount":"1061","channel_description":"","channel_totaluploadviews":"0","alias":"lotto-lotto-plus-1-and-lotto-plus-2-draw-2012-11-april-2020","rawdata":"","datalink":"https:\/\/www.googleapis.com\/youtube\/v3\/videos?id=chHfFxVi9QI&part=id,snippet,contentDetails,statistics&key=AIzaSyC1Xvk2GUdb_N3UiFtjsgZ-uMviJ_8MFZI"}]}
It is a POST type request, and so I tried to follow this answer, but cannot find onclick values indicating the data submitted with the form. Moreover, the request URL for 'LOTTO DRAW 2012' is identical to that for 'LOTTO DRAW 2011', so there is no unique identifier for the particular draw being passed with the URL itself. Thus it is not clear to me how the unique request for the results of a particular draw is made.
Hence, the smaller question is, given a particular LOTTO draw number or draw date, how does one find out the unique identifier that is used to make the POST request for the data pertaining to that draw specifically?
The larger question is, if one is able to obtain such unique identifiers for all the historical draws, how can one generate the JSON drawDetails object for all the historical draws in turn, or otherwise complete the scraping operation?
You are right - the contents on the page are updated by javascript via an ajax request. The server returns a json string in response to an http POST request. With POST requests, the server's response is determined not only by the url you request, but by the body of the message you send to the server. In this case, your body is a simple form with 3 fields: gameName, which is always LOTTO, isAjax which is always true, and drawNumber, which is the field you want to vary.
If you are using httr, you specify these fields as a named list in the body parameter of the POST function.
Once you have the response for each draw, you will want to parse the json into an R-friendly format such as a list or data frame using a library such as jsonlite. From looking at the structure of this particular json, it makes most sense to extract the component $data$drawDetailsand make that a one-row dataframe. This will allow you to bind several draws together into a single data frame.
Here is a function that does all that for you:
lotto_details <- function(draw_numbers)
{
do.call("rbind", lapply(draw_numbers, function(x)
{
res <- httr::POST(paste0("https://www.nationallottery.co.za/index.php",
"?task=results.redirectPageURL&",
"Itemid=265&option=com_weaver&",
"controller=lotto-history"),
body = list(gameName = "LOTTO", drawNumber = x, isAjax = "true"))
as.data.frame(jsonlite::fromJSON(httr::content(res, "text"))$data$drawDetails)
}))
}
Which you use like this:
lotto_details(2009:2012)
#> drawNumber drawDate nextDrawDate ball1 ball2 ball3 ball4 ball5 ball6
#> 1 2009 2020/04/01 2020/04/04 51 15 7 32 42 45
#> 2 2010 2020/04/04 2020/04/08 43 4 21 24 10 3
#> 3 2011 2020/04/08 2020/04/11 42 43 8 18 2 29
#> 4 2012 2020/04/11 2020/04/15 48 6 43 41 25 45
#> bonusBall div1Winners div1Payout div2Winners div2Payout div3Winners
#> 1 1 0 0 0 0 21
#> 2 22 0 0 0 0 31
#> 3 34 0 0 0 0 21
#> 4 38 1 10546013.8 0 0 28
#> div3Payout div4Winners div4Payout div5Winners div5Payout div6Winners
#> 1 8455.3 60 2348.7 1252 189 1786
#> 2 6004.3 71 2080.6 1808 137.3 2352
#> 3 8584.5 60 2384.6 1405 171.1 2079
#> 4 7676.4 62 2751.4 1389 206.3 1872
#> div6Payout div7Winners div7Payout div8Winners div8Payout rolloverAmount
#> 1 115.2 24664 50 19711 20 3809758.17
#> 2 91.7 35790 50 25981 20 5966533.86
#> 3 100.5 27674 50 21895 20 8055430.87
#> 4 133 28003 50 20651 20 0
#> rolloverNumber totalPrizePool totalSales estimatedJackpot
#> 1 2 6198036.67 9879655 6000000
#> 2 3 9073426.56 11696905 8000000
#> 3 4 10649716.37 10406895 10000000
#> 4 0 13280236.5 11610950 2000000
#> guaranteedJackpot drawMachine ballSet status winners millionairs
#> 1 0 RNG2 RNG published 47494 0
#> 2 0 RNG2 RNG published 66033 0
#> 3 0 RNG2 RNG published 53134 0
#> 4 0 RNG2 RNG published 52006 1
#> gpwinners wcwinners ncwinners ecwinners mpwinners lpwinners fswinners
#> 1 47494 0 0 0 0 0 0
#> 2 66033 0 0 0 0 0 0
#> 3 53134 0 0 0 0 0 0
#> 4 52006 0 0 0 0 0 0
#> kznwinners nwwinners
#> 1 0 0
#> 2 0 0
#> 3 0 0
#> 4 0 0
Created on 2020-04-13 by the reprex package (v0.3.0)
The question already has a satisfactory answer (see above) that I've accepted. I simultaneously arrived at a nearly identical solution; I add it here only because it explicitly covers the full range of available draw numbers and will automatically detect the most recent draw number so that the code can be run 'as is' in the future, provided the National Lottery website design remains the same.
theurl <- "https://www.nationallottery.co.za/index.php?task=results.redirectPageURL&Itemid=265&option=com_weaver&controller=lotto-history"
x <- rvest::html_text(xml2::read_html(theurl))
preceding_string <- "LOTTO, LOTTO PLUS 1 AND LOTTO PLUS 2 DRAW "
drawnums <- as.integer(vapply(gregexpr(preceding_string, x)[[1]] + nchar(preceding_string),
function(k) substr(x, start = k, stop = k + 3), NA_character_))
drawnumrange <- 1506:max(drawnums)
response <- lapply(drawnumrange, function(d) httr::POST(url = theurl,
body = list(gameName = "LOTTO", drawNumber = as.character(d), isAjax =
"true"), encode = "form"))
jsondat <- lapply(response, function(r) jsonlite::parse_json(r)$data$drawDetails)
lottotable <- as.data.frame(do.call(rbind, jsondat))
numericcols <- c(1, 4:32, 36:37)
lottotable[numericcols] <- sapply(lottotable[numericcols], as.numeric)
xlsx::write.xlsx2(lottotable[1:37], "lottotable.xlsx", row.names = FALSE)

How to get count 0 if data is not present in database using mySQL

I'm showing up monthly user registered on my app. For that, I have used the below query, which is working fine. But with this query, if no user registered in the month of June then no data is there against June. I want a row with month June and all other information set to 0. Can anyone please help me out with this?
SELECT Month(createdon), count(*) as users,COUNT(if(roleid=1,1,NULL)) as instructor, COUNT(if(roleid=2,1,NULL)) as student FROM user_profile where Year(createdon) = Year(Now()) group by MONTH(createdon);
I am getting the output as:
Month(created on) | users | instructor | student |
3 | 4 | 3 | 1 |
4 | 7 | 5 | 2 |
Here, Month 3 and 4 corresponds to March and April respectively.
But the actual output is:
Month(created on) | users | instructor | student |
1 | 0 | 0 | 0 |
2 | 0 | 0 | 0 |
3 | 4 | 3 | 1 |
4 | 7 | 5 | 2 |
5 | 0 | 0 | 0 |
6 | 0 | 0 | 0 |
You can try this:
SELECT MONTH(createdon) AS month, COUNT(*) AS users, COUNT(IF(roleid=1,1,NULL)) AS instructor, COUNT(IF(roleid=2,1,NULL)) AS student
FROM user_profile
WHERE (YEAR(createdon) = YEAR(NOW()))
GROUP BY MONTH(createdon)
UNION
SELECT M.month, 0, 0, 0
FROM (SELECT 1 AS month UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12) AS M
WHERE (M.month <= MONTH(NOW()))
AND (NOT EXISTS (SELECT * FROM user_profile WHERE (MONTH(createdon) = M.month)));
I had the same experience
So just use
SELECT IF( EXISTS (SELECT * FROM user_profile WHERE MONTH(createdon)= 'yourmonth')
,SELECT
Month(createdon),
COUNT(*) AS users,
COUNT(if(roleid=1,1,NULL)) AS instructor,
COUNT(if(roleid=2,1,NULL)) AS student
FROM user_profile
WHERE Year(createdon) = Year(Now())
Group BY MONTH(createdon)
,0)
You could collect the sorted SQL result and iterate a custom range and insert either the given data or an empty result set.
function getRange(from, to, result) {
var i, j = 0;
for (i = from; i <= to; i++) {
if (result[j] && i === result[j][0]) {
console.log(...result[j++]); // slq result
} else {
console.log(i, 'empty row'); // row with zeroes
}
}
}
getRange(1, 6, [[3, 2, 5], [4, 3, 2]]);
You are not seeing row with 0 value because data for given month is not there in your table and groupby will show data of months that are present.
You can generate a month list for given year -
select TO_CHAR((current_date - interval '1 month' * a),'MM') AS mm FROM generate_series(1,12,1) AS s(a)
it will generate value like
01
02
03
.
.
Then you can write a subquery with this table and do left join with your user_profile table and you will get data as you have specified.
For more read, go through this link.
You need to start with a list of months. This can be accomplished with a derived table:
SELECT m.mon, COUNT(up.createdon) as users,
SUM(up.roleid = 1) as instructor,
SUM(up.roleid = 2) as student
FROM (SELECT 1 as mon UNION ALL
SELECT 2 as mon UNION ALL
SELECT 3 as mon UNION ALL
SELECT 4 as mon UNION ALL
SELECT 5 as mon UNION ALL
SELECT 6 as mon
) m LEFT JOIN
user_profile up
ON m.mon = MONTH(up.createdon) AND
YEAR(createdon) = YEAR(Now())
GROUP BY m.mon;
If you have a calendar table or numbers table, you can use that instead of the derived table.

Categories