I'm having a problem with a function i'm working on. I am able to get the proper data, just not print out the names of the month as well.
sample output i'm getting:
| Month | High | Low | Avg | Precip |
|-----------|-------|-------|-------|---------|
1 | 9.8 | -26.2 | -7.8 | 55.3 |
2 | 7.5 | -23.3 | -8.6 | 33.1 |
3 | 14.2 | -19.6 | -4.7 | 33.2 |
4 | 23.7 | -5.3 | 6.2 | 56.8 |
5 | 33.0 | -0.6 | 13.9 | 62.7 |
6 | 32.1 | 8.0 | 19.7 | 69.7 |
7 | 34.9 | 12.6 | 22.2 | 181.8 |
8 | 31.5 | 11.0 | 20.9 | 69.2 |
9 | 34.1 | 5.0 | 16.1 | 69.0 |
10 | 24.8 | -2.9 | 10.8 | 56.9 |
11 | 16.0 | -12.8 | 2.1 | 36.2 |
12 | 15.6 | -17.8 | -4.2 | 65.8
I want to conver digits 1-12 to there proper month names. Ie: 1 = January.
void printMonthlyStatistic(int month,const struct MonthlyStatistic* monthly)
is what the function looks like
for(i=0;i<12;i++){
printMonthlyStatistic(i+1,&monthly[i])
and is called in main as such.
Any help onto where to look for the proper method to complete this would be great. Thanks!
You should use an array to store the name of the month, like:
const char * months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
You can get the name of the month easily, for example, if index = 1, then
months[index -1]
will give you the first month name: January.
The following code:
for (int i = 0; i < 12; ++i) {
printf("%s ", months[i]);
}
will output:
January February March April May June July August September October
November December
You can maintain Month Array of String like
char months_names[12] = {Jan, Feb, Mar, Apr, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
You can Just paas integer number month to array for getting String value
months_names["Integrer Value"] You will get String name of month.
Related
Here is an excerpt of my table data:
|deviceid | |failcount| started | ended |
| a1078 | | 2 | 2020-12-07 14:51:33 | 2020-12-07 17:30:16|
|a1006 | | 2 | 2020-12-09 15:58:01 | 2020-12-09 23:59:59|
|a1006 | | 2 | 2020-12-10 00:00:00 | 2020-12-10 16:40:02|
|a136 | | 71 | 2020-12-18 10:12:19 | 2020-12-18 23:59:59|
|a136 | | 71 | 2020-12-19 00:00:00 | 2020-12-19 04:27:23|
|a1078 | | 36 | 2020-12-21 10:07:09 | 2020-12-21 14:36:40|
What I am trying to get to is to get the earliest start date and the latest end date for each deviceid, BUT for only the same failcount number. The failcount number is the # of failures for each deviceid, so multiple deviceid's can have the same failcount number (should be very few).
This is what im trying to get to:
|deviceid| |failcount| | started | | ended |
|a1078 | | 2 | | 2020-12-07 14:51:33 | |2020-12-07 17:30:16|
|a1006 | | 2 | |2020-12-09 15:58:01 | |2020-12-10 16:40:02|
|a136 | | 71 | |2020-12-18 10:12:19 | |2020-12-19 04:27:23|
|a1078 | | 36 | | 2020-12-21 10:07:09 | |2020-12-21 14:36:40|
I've tried variations of min/max but can't figure out how to keep different failcounts from same deviceid from being combined - for instance, in the above for deviceid a1078, I don't want the started for failcount 2 and the ended for failcount 36.
What I have so far is this but it is combining different failcounts for the same deviceid:
select deviceid
, min(started) as started
, max(started) as ended
from dayfail
where eventno = '600509'
and Convert(char(6),started, 112) = '202012'
group by deviceid
Thx in advance for any assistance to this sql newbie ;)
With this Query I get this result. The idea is i have a date of the product that is sold. When check if the date is between date_start and date_end of the marketing table, if so put that price in the marketingprice.
In some cases there is no end. This mean it's still running and has no end date. We still use them.
Because there is no end date I want to use the date of today. So if E (date_end) is empty , use the today date if not then use E
=query(Marketing!$B$2:E,
"select C,D where B='" & D2 & "' and
D<=date '"&TEXT(E2,"yyyy-MM-dd")&"' and
date'"&TEXT(today(),"yyyy-MM-dd")&"'>=date '"&TEXT(E2,"yyyy-MM-dd")&"' ")
+------------+---------------+--------+-----------------+----------+----------------+
| product_no | product_price | amount | deliver_country | datum | marketingprice |
+------------+---------------+--------+-----------------+----------+----------------+
| 1001 | 2.8 | 2 | de | 2-1-2020 | |
+------------+---------------+--------+-----------------+----------+----------------+
+-----+------------+
| 3.2 | 01-01-2020 |
| 1.2 | 02-01-2020 |
+-----+------------+
I want to use IF(isblank(E),date'"&TEXT(TODAY(),"yyyy-MM-dd")&"', E)
Then the code will be
=query(Marketing!$B$2:E,
"select C,D where B='" & D2 & "' and
D<=date '"&TEXT(E2,"yyyy-MM-dd")&"' and
IF(isblank(E),date'"&TEXT(today(),"yyyy-MM-dd")&"',E)>=date '"&TEXT(E2,"yyyy-MM-dd")&"' ")
Then I get a error:
QUERY: PARSE_ERROR: Encountered " "IF "" at line 1, column 58.
Was expecting one of: "(" ... "(" ...
Marketing Table
+---------+---------+-------+-------------+------------+
| channel | country | price | date_start | date_end |
+---------+---------+-------+-------------+------------+
| Google | de | 3.2 | 01-01-2020 | 01-01-2020 |
| Google | de | 1.2 | 02-01-2020 | |
| Amazon | en | 5.4 | 01-01-2020 | |
+---------+---------+-------+-------------+------------+
Output how it should be
+------------+---------------+--------+-----------------+----------+----------------+
| product_no | product_price | amount | deliver_country | datum | marketingprice |
+------------+---------------+--------+-----------------+----------+----------------+
| 1001 | 2.8 | 2 | de | 2-1-2020 | 1.2 |
| 1002 | 3.8 | 4 | en | 3-1-2020 | 5.4 |
| 1001 | 2.8 | 1 | de | 1-1-2020 | 3.2 |
+------------+---------------+--------+-----------------+----------+----------------+
In mysql I use this code :
b.start_date <= date(i.system_created) AND
coalesce(b.end_date,now()) >= date(i.system_created)
Solution i found myself:
=QUERY(Marketing!$B$2:$E;IF(Marketing!E$2:E="";
"select E where B ='"&D2&"' and D <=date'"&TEXT(E2;"yyyy-MM-dd")&"' and date'"&TEXT(VANDAAG();"yyyy-MM-dd")&"' >=date'"&TEXT(E2;"yyyy-MM-dd")&"' limit 1";
"select E where B ='"&D2&"' and D <=date'"&TEXT(E2;"yyyy-MM-dd")&"' and E >=date'"&TEXT(E2;"yyyy-MM-dd")&"'"
);0)
try:
=ARRAYFORMULA(IFERROR(QUERY(
{Marketing!B$2:D\ IF(Marketing!E$2:E=""; TODAY(); Marketing!E$2:E)};
"select Col2
where Col1 = '"&D2&"'
and Col3 <= date '"&TEXT(E2;"yyyy-MM-dd")&"'
and Col4 <= "&TODAY()&"
limit 1"; 0)))
You could use Apps Script to solve this issue.
How does it work?
Assign Sales data (D2:E7) to sales variable, Marketing data (B2:E7) to marketing variable.
in for loop through sales and if sale_date < date_start set cell value as marketing_cost - 1
Below you can find a screenshot attached before and after.
function worker(){
let ss = SpreadsheetApp.getActive();
let sheetSales = ss.getSheetByName("Sales");
let sheetMarketing = ss.getSheetByName("Marketing");
// 1.
let sales = sheetSales.getRange("D2:E7").getValues();
/** sales
[
[de, 02-01-2020],
[de, 03-01-2020],
[de, 04-01-2020],
[de, 06-01-2020],
[de, 10-01-2020],
[en, 10-01-2020]
]
*/
let marketing = sheetMarketing.getRange("B2:E7").getValues();
/** marketing
[
[de, 3.2, 01-01-2020, 02-01-2020],
[de, 1.2, 03-01-2020, 04-01-2020],
[de, 4.4, 05-01-2020, 06-01-2020],
[de, 8.8, 07-01-2020, 08-01-2020],
[de, 9.9, 09-01-2020, 25-02-2020],
[en, 5.4, 01-01-2020, 25-02-2020]
]
*/
let sale_date,
date_start,
date_end,
marketing_cost = [];
for(let i = 0; i < sales.length; i++){
sale_date = new Date(sales[i][1]);
date_start = new Date(marketing[i][2]);
date_end = new Date(marketing[i][3]);
marketing_cost.push(marketing[i][1]);
// 2.
if(sale_date < date_start){
sheetSales.getRange(2+i, 6).setValue(marketing_cost[i-1]);
}else{
sheetSales.getRange(2+i, 6).setValue(marketing_cost[i]);
}
}
}
Before:
After:
Reference:
Spreadsheet Service
initially I was dealing with a dataset that looked something like this:
+------+--------+-----------+-------+
| date | geo | variables | value |
+------+--------+-----------+-------+
| 1981 | Canada | var1 | # |
| 1982 | Canada | var1 | # |
| 1983 | Canada | var1 | # |
| ... | ... | ... | ... |
| 2015 | Canada | var2 | # |
| 1981 | Canada | var2 | # |
| 1982 | Canada | var2 | # |
| ... | ... | ... | ... |
| 2015 | Canada | var2 | # |
| 1981 | Quebec | var1 | # |
| 1982 | Quebec | var1 | # |
| 1983 | Quebec | var1 | # |
| ... | ... | ... | ... |
| 2015 | Quebec | var2 | # |
| 1981 | Quebec | var2 | # |
| 1982 | Quebec | var2 | # |
| ... | ... | ... | ... |
| 2015 | Quebec | var2 | # |
+------+--------+-----------+-------+
So I have 35 time periods, two countries and two variables. I would like to transform the table in Stata for it to look like this:
+------+--------+------+------+
| date | geo | var1 | var2 |
+------+--------+------+------+
| 1981 | Canada | # | # |
| 1982 | Canada | # | # |
| ... | ... | ... | ... |
| 2015 | Canada | # | # |
| 1981 | Quebec | # | # |
| 1982 | Quebec | # | # |
| ... | ... | ... | ... |
| 2015 | Quebec | # | # |
+------+--------+------+------+
However, I'm not having much success with this. I tried to separate the different observations into variables with the command:
separate value, by(variables) generate(var)
Which creates something like this:
+------+--------+------+------+
| date | geo | var1 | var2 |
+------+--------+------+------+
| 1981 | Canada | # | . |
| 1982 | Canada | # | . |
| ... | ... | ... | ... |
| 2015 | Canada | # | . |
| 1981 | Canada | . | # |
| 1982 | Canada | . | # |
| ... | ... | ... | ... |
| 2015 | Canada | . | # |
| 1981 | Quebec | # | . |
| 1982 | Quebec | # | . |
| ... | ... | ... | ... |
| 2015 | Quebec | # | . |
| 1981 | Quebec | . | # |
| 1982 | Quebec | . | # |
| ... | ... | ... | ... |
| 2015 | Quebec | . | # |
+------+--------+------+------+
Which contains a lot of useless missing values.
So, more specifically, I would like something to bring me directly to Table A to B (i.e. without using separate), or a solution to fix Table C into B.
Thanks a lot.
Without sample data, my answer will have to be untested. I think something like the following will get you started in the right direction.
reshape wide value, i(date geo) j(variables) string
Note that this assumes the contents of your variables variable are suitable for use as variable names. For example, a value of 1potato for variables would be a problem.
In any event,
help reshape
should be your first stop.
Added in response to comment: Here is some data I made up and a demonstration that reshape works for this data. Perhaps you can explain how this data differs from the real data. Your error message suggests that for some combination of date and geo, a particular value of variables occurs more than once.
. list, sepby(geo)
+----------------------------------+
| date geo variab~s value |
|----------------------------------|
1. | 1981 Canada var1 111 |
2. | 1982 Canada var1 211 |
3. | 1983 Canada var1 311 |
4. | 1981 Canada var2 112 |
5. | 1982 Canada var2 212 |
6. | 1983 Canada var2 312 |
|----------------------------------|
7. | 1981 Quebec var1 121 |
8. | 1982 Quebec var1 221 |
9. | 1983 Quebec var1 321 |
10. | 1981 Quebec var2 122 |
11. | 1982 Quebec var2 222 |
12. | 1983 Quebec var2 322 |
+----------------------------------+
. reshape wide value, i(geo date) j(variables) string
(note: j = var1 var2)
Data long -> wide
-----------------------------------------------------------------------------
Number of obs. 12 -> 6
Number of variables 4 -> 4
j variable (2 values) variables -> (dropped)
xij variables:
value -> valuevar1 valuevar2
-----------------------------------------------------------------------------
. rename (value*) (*)
. list, sepby(geo)
+-----------------------------+
| date geo var1 var2 |
|-----------------------------|
1. | 1981 Canada 111 112 |
2. | 1982 Canada 211 212 |
3. | 1983 Canada 311 312 |
|-----------------------------|
4. | 1981 Quebec 121 122 |
5. | 1982 Quebec 221 222 |
6. | 1983 Quebec 321 322 |
+-----------------------------+
.
I want all my lines to line up correctly, but for some reason when i print it out it looks crooked, like this:
Weather summary for 2013
| Month | High | Low | Avg | Precip |
|-----------|-------|-------|-------|---------|
| January| 9.8 | -26.2 | -7.8 | 55.3 |
| February| 7.5 | -23.3 | -8.6 | 33.1 |
| March| 14.2 | -19.6 | -4.7 | 33.2 |
| April| 23.7 | -5.3 | 6.2 | 56.8 |
| May| 33.0 | -0.6 | 13.9 | 62.7 |
| June| 32.1 | 8.0 | 19.7 | 69.7 |
| July| 34.9 | 12.6 | 22.2 | 181.8 |
| August| 31.5 | 11.0 | 20.9 | 69.2 |
| September| 34.1 | 5.0 | 16.1 | 69.0 |
| October| 24.8 | -2.9 | 10.8 | 56.9 |
| November| 16.0 | -12.8 | 2.1 | 36.2 |
| December| 15.6 | -17.8 | -4.2 | 65.8 |
my code for the printf call:
printf("| %10s| %-4.1f | %-4.1f | %-4.1f | %-4.1f |\n",month_names[month - 1] ,
monthly->maxTemperature,monthly->minTemperature, monthly->averageTemperature, monthly->totalPrecipitation);
Thanks!
For this kind of formatted output, all you need is a rough estimation of the width of each field, then let printf do all the formatting, instead of counting the spaces then coming up with something like %4.1f..
For example in this case, start with the header, give a rough estimate of the width of each header fields:
printf( "|%-20s|%-10s|%-10s|%-10s|%-10s|\n", "Month", "High", "Low", "Avg", "Precip" );
Then for the following rows, use the same width, just replace %s with %f for float numbers. You can manipulate how many position after the decimal point.
printf( "|%-20s|%-10.1f|%-10.1f|%-10.1f|%-10.1f|\n", ...
Since you are using -4.1f as your printf specifier, you will always get 1 space after the decimal point, so 4 total spaces isn't enough for the negative numbers, and printf is adding an extra space in the output for you. So, you will need to use -5.1f to get enough space for one decimal point and the - sign. So, if you end up with a number like -123.4, you won't get proper alignment again.
having trouble debugging the reason i'm getting a space between oct-nov and nov-dec. here is the code:
if (month == 1)
printf("jan");
if (month == 2)
printf("feb");
if (month == 3)
printf("march");
if (month == 4)
printf("apr");
if (month == 5)
printf("may");
if (month == 6)
printf("jun");
if (month == 7)
printf("jul");
if (month == 8)
printf("aug");
if (month == 9)
printf("sept");
if (month == 10)
printf("oct");
if (month == 11)
printf("nov");
if (month == 12)
printf("dec");
printf(" %c | %.1f | %.1f | %.1f | %.1f |\n", month, monthly->maxTemperature,
monthly->minTemperature, monthly->averageTemperature, monthly->totalPrecipitation);
have tried changing the spacing as well but its always between those 2 months for some reason. Thanks!
edit:
it is part of this function :
void printMonthlyStatistic(int month,const struct MonthlyStatistic* monthly)
and is called in main program like this:
for(i=0;i<12;i++){
printMonthlyStatistic(i+1,&monthly[i])
my sample output:
| Month | High | Low | Avg | Precip |
|-----------|-------|-------|-------|---------|
jan | 9.8 | -26.2 | -7.8 | 55.3 |
feb | 7.5 | -23.3 | -8.6 | 33.1 |
march | 14.2 | -19.6 | -4.7 | 33.2 |
apr | 23.7 | -5.3 | 6.2 | 56.8 |
may | 33.0 | -0.6 | 13.9 | 62.7 |
jun | 32.1 | 8.0 | 19.7 | 69.7 |
jul | 34.9 | 12.6 | 22.2 | 181.8 |
aug | 31.5 | 11.0 | 20.9 | 69.2 |
sept | 34.1 | 5.0 | 16.1 | 69.0 |
oct
| 24.8 | -2.9 | 10.8 | 56.9 |
nov
| 16.0 | -12.8 | 2.1 | 36.2 |
dec
| 15.6 | -17.8 | -4.2 | 65.8 |
%c prints a character with the specified charcode, and if you use ASCII code, 10 is newline and 11 is vertical tab.
Also, you should use an array instead of writing those too-many ifs.
Try this:
static const char *month_names[] = {"jan", "feb", "march", "apr", "may", "jun", "jul", "aug", "sept", "oct", "nov", "dec"};
printf("%-11s| %.1f | %.1f | %.1f | %.1f |\n",
1 <= month && month <= 12 ? month_names[month - 1] : "", monthly->maxTemperature,
monthly->minTemperature, monthly->averageTemperature, monthly->totalPrecipitation);
Your problem is the %c which prints a char. The ASCII value NewLine is 10 and the Vertical Tab is 11: