Yii2 querybuilder sum with condition - yii2

This is my query.
$query1 = (new \yii\db\Query())
->select(['day', 'modeler', 'sum(ifnull(differ, 0)) + sum(ifnull(reworkdiffer, 0)) as total'])
->from('loghour3d')
->groupBy(['day', 'modeler'])
->orderBy(['day'=>SORT_DESC]);
This is my table structure.
day modeler differ handover reworkdiffer
2018-1-05 star 5
2018-1-06 star star1 3
2018-1-06 star1 3
So i want to sum differ field grouping by day and modeler. My code get me this result:
day modeler total
2018-1-05 star 5
2018-1-06 star 8
2018-1-06 star1 3
Above, In the date 2018-1-06, modeler star didn't work, instead handover to star1, but total is sum to star instead of star1. Below is the result i want
day modeler total
2018-1-05 star 5
2018-1-06 star 0
2018-1-06 star1 6
Is there anyway for me to archive this with querybuilder in yii2? Please advice
Thank you.

Related

How to sum specific rows and columns in SQL?

pnr mnd pris
1 1 600
1 7 900
2 1 600
2 7 600
3 1 40
3 7 40
I have trouble how to sum specific rows on the columns. Looking at the above, the table is called travel and it has 3 columns:
pnr - Personal Number
mnd - Month
Pris - Price
So what I want is to sum total of the price for the a specific month, so in this case, it should be 1240 USD and month 1. For the month 7, it should be 1540 USD.
I have trouble to do the query correct. So far from I have tried is this:
SELECT t.rnr, t.mnd, SUM(t.pris)
FROM travel AS t
WHERE t.mnd = 1
The result I get is 3720 USD which I have no idea how the SQL managed to calculate this for me.
Appreciate if someone could please help me out!
For this you need to drop the pnr column from the output (it is not relevant and will cause your data to split) and add a GROUP BY:
SELECT t.mnd, SUM(t.pris)
FROM travel AS t
WHERE t.mnd = 1
GROUP BY t.mnd
Live demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=b34ec2bb9c077c2d74ffc66748c5c142
(The use of an aggregate function without grouping, as you've got now, is not a standard SQL feature and can often be turned off in MySQL. If turned on, you might not always get the result you expected/intended.)
just group your result with mnd column
SELECT t.mnd, SUM(t.pris)
FROM travel AS t
group by t.mnd

MYSQL How to perform custom month difference between two dates in MYSQL?

My requirement is to compute the total months and then broken months separately between 2 dates (ie first date from table and second date is current date). If broken months total count is > 15 then account it as one month experience and if its les than 15 don't account that as 1 month experience.
Assume I have a date on table as 25/11/2018 and current date is 06/01/2019;
the full month in between is December, so 1 month experience; and broken months are November and January, so now I have to count the dates which is 6 days in Nov and 6 days in Jan, so 12 days and is <= (lte) 15 so total experience will be rounded to 1 month experience
I referred multiple questions related to calculating date difference in MYSQL from stackoverflow, but couldn't find any possible options. The inbuilt functions in MYSQL TIMESTAMPDIFF, TIMEDIFF, PERIOD_DIFF, DATE_DIFF are not giving my required result as their alogrithms are different from my calculation requirement.
Any clue on how to perform this calculation in MYSQL and arrive its result as part of the SQL statement will be helpful to me. Once this value is arrived, in the same SQL, that value will be validated to be within a given value range.
Including sample table structure & value:
table_name = "user"
id | name | join_date
---------------------
1| Sam | 25-11-2017
2| Moe | 03-04-2017
3| Tim | 04-07-2018
4| Sal | 30-01-2017
5| Joe | 13-08-2018
I wanted to find out the users from above table whose experience is calculated in months based on the aforementioned logic. If those months are between either of following ranges, then those users are fetched for further processing.
table_name: "allowed_exp_range"
starting_exp_months | end_exp_months
-------------------------------------
0 | 6
9 | 24
For ex: Sam's experience till date (10-12-2018) based on my calculation is 12+1 month = 13 months. Since 13 is between 9 & 24, Sam's record is one of the expected output.
I think this query will do what you want. It uses
(YEAR(CURDATE())*12+MONTH(CURDATE()))
- (YEAR(STR_TO_DATE(join_date, '%d-%m-%Y'))*12+MONTH(STR_TO_DATE(join_date, '%d-%m-%Y'))) -
- 1
to get the number of whole months of experience for the user,
DAY(LAST_DAY(STR_TO_DATE(join_date, '%d-%m-%Y')))
- DAY(STR_TO_DATE(join_date, '%d-%m-%Y'))
+ 1
to get the number of days in the first month, and
DAY(CURDATE())
to get the number of days in the current month. The two day counts are summed and if the total is > 15, 1 is added to the number of whole months e.g.
SELECT id
, name
, (YEAR(CURDATE())*12+MONTH(CURDATE())) - (YEAR(STR_TO_DATE(join_date, '%d-%m-%Y'))*12+MONTH(STR_TO_DATE(join_date, '%d-%m-%Y'))) - 1 -- whole months
+ CASE WHEN DAY(LAST_DAY(STR_TO_DATE(join_date, '%d-%m-%Y'))) - DAY(STR_TO_DATE(join_date, '%d-%m-%Y')) + 1 + DAY(CURDATE()) > 15 THEN 1 ELSE 0 END -- broken month
AS months
FROM user
We can use this expression as a JOIN condition between user and allowed_exp_range to find all users who have experience within a given range:
SELECT u.id
, u.name
, a.starting_exp_months
, a.end_exp_months
FROM user u
JOIN allowed_exp_range a
ON (YEAR(CURDATE())*12+MONTH(CURDATE())) - (YEAR(STR_TO_DATE(u.join_date, '%d-%m-%Y'))*12+MONTH(STR_TO_DATE(u.join_date, '%d-%m-%Y'))) - 1
+ CASE WHEN DAY(LAST_DAY(STR_TO_DATE(u.join_date, '%d-%m-%Y'))) - DAY(STR_TO_DATE(u.join_date, '%d-%m-%Y')) + 1 + DAY(CURDATE()) > 15 THEN 1 ELSE 0 END
BETWEEN a.starting_exp_months AND a.end_exp_months
Output (for your sample data, includes all users as they all fit into one of the experience ranges):
id name starting_exp_months end_exp_months
1 Sam 9 24
2 Moe 9 24
3 Tim 0 6
4 Sal 9 24
5 Joe 0 6
I've created a small demo on dbfiddle which demonstrates the steps in arriving at the result.

use a transaction database to calculate the probability of an item appearing in a future transaction using R or SQL

I have a database of transactions like in the table below
user_id order_id order_number product_name n
<int> <int> <int> <fctr> <int>
1 11878590 3 Pistachios 1
1 11878590 3 Soda 1
1 12878790 4 Yogurt 1
1 12878790 4 Cheddar Popcorn 1
1 12878790 4 Cinnamon Toast Crunch 1
2 12878791 11 Milk Chocolate Almonds 1
2 12878791 11 Half & Half 1
2 12878791 11 String Cheese 1
11 12878792 19 Whole Milk 1
11 12878792 19 Pistachios 1
11 12878792 19 Soda 1
11 12878792 19 Paper Towel Rolls 1
The table has multiple users who each have multiple transactions. Some users only have 3 transactions, other users have 15, etc. This is all in one table.
I'm trying to calculate a transition matrix for a markov model. I want to find the probability that an item will be in a new basket given that it was present in the previous basket of transactions.
I want my final table to look something like this
user_id product_name probability_present probability_absent
1 Soda .5 .5
1 Pistachios .5 .5
I'm having trouble figuring out how to get the data into a form so that I can calculate the probabilities and specifically coming up with a way to compare all of the t,t-1 combinations.
I have code that I've written to get things into this form, but I'm stuck at this point. I've written my code using the dplyr R package, but I could translate something in SQL into the R code. I can post my code in R if it will be helpful, but it is pretty simple at this point as I just had to do a few joins to get the table into this shape.
What else do I have to do to get the table/values that I'm trying to calculate?
This seems to give you the desired probabilities:
SELECT user_id,
product_name,
COUNT(DISTINCT order_number) / COUNT(*) AS prob_present,
1 - COUNT(DISTINCT order_number) / COUNT(*) AS prob_absent
FROM tbl
WHERE user_id = 1
GROUP BY user_id, product_name;
Or at least it gives you the numbers you have. If this is not right, please provide a slightly more complex example dataset.

MS Access: Using Single form to enter query parameters in MS access

compliment of the day.
Based on the previous feedback received,
After creating a Ticket sales database in MS Access. I want to use a single form to Query the price of a particular ticket at a particular month and have the price displayed back in the form in a text field or label.
Below are sample tables and used query
CompanyTable
CompID CompName
A Ann
B Bahn
C Can
KK Seven
- --
TicketTable
TicketCode TicketDes
10 Two people
11 Monthly
12 Weekend
14 Daily
TicketPriceTable
ID TicketCode Price ValidFrom
1 10 $35.50 8/1/2010
2 10 $38.50 8/1/2011
3 11 $20.50 8/1/2010
4 11 $25.00 11/1/2011
5 12 $50.50 12/1/2010
6 12 $60.50 1/1/2011
7 14 $15.50 2/1/2010
8 14 $19.00 3/1/2011
9 10 $40.50 4/1/2012
Used query:
SELECT TicketPriceTable.Price
FROM TicketPriceTable
WHERE (((TicketPriceTable.ValidFrom)=[DATE01]) AND ((TicketPriceTable.TicketCode)=[TCODE01]));
In MS Access, a mini boxes pops up to enter the parameters when running the query. How can I use a single form to enter the parameters for [DATE01] and [TCODE01]. and the price displayed in the same form in a textfield (For further calculations).
Such as 'Month' field equals to input to [DATE01] parameter
'Ticket Code' equals to input for [TCODE01] parameter
Textfield equals to output of the query result (Ticket price)
If possible, I would like to use only the Month and Year in this format MM/YYYY.The day is not necessarry. How can I achieve it in MS Access?
If any question, please don't hesitate to ask
Thanks very much for your time and anticipated feedback.
You can refer to the values in the form fields by using expressions like: [Forms]![NameOfTheForm]![NameOfTheField]
Entering up to 300 different types of tickets
Answer to your comment referring to Accessing data from a ticket database, based on months in MS Access)
You can use Cartesian products to create a lot of records. If you select two tables in a query but do not join them, the result is a Cartesian product, which means that every record from one table is combined with every record from the other.
Let's add a new table called MonthTable
MonthNr MonthName
1 January
2 February
3 March
... ...
Now if you combine this table containing 12 records with your TicketTable containing 4 records, you will get a result containing 48 records
SELECT M.MonthNr, M.MonthName, T.TicketCode, T.TicketDes
FROM MonthTable M, TicketTable T
ORDER BY M.MonthNr, T.TicketCode
You get something like this
MonthNr MonthName TicketCode TicketDes
1 January 10 Two people
1 January 11 Monthly
1 January 12 Weekend
1 January 14 Daily
2 February 10 Two people
2 February 11 Monthly
2 February 12 Weekend
2 February 14 Daily
3 March 10 Two people
3 March 11 Monthly
3 March 12 Weekend
3 March 14 Daily
... ... ... ...
You can also get the price actually valid for a ticket type like this
SELECT TicketCode, Price, ActualPeriod AS ValidFrom
FROM (SELECT TicketCode, MAX(ValidFrom) AS ActualPeriod
FROM TicketPriceTable
WHERE ValidFrom <= Date
GROUP BY TicketCode) X
INNER JOIN TicketPriceTable T
ON X.TicketCode = T.TicketCode AND X.ActualPeriod=T.ValidFrom
The WHERE ValidFrom <= Date is in case that you entered future prices.
Here the subquery selects the actually valid period, i.e. the ValidFrom that applies for each TicketCode. If you find sub-selects a bit confusing, you can also store them as query in Access or as view in MySQL and base a subsequent query on them. This has the advantage that you can create them in the query designer.
Consider not creating all your 300 records physically, but just getting them dynamically from a Cartesian product.
I let you put all the pieces together now.
In Access Forms you can set the RecordSource to be a query, not only a table. This can be either the name of a stored query or a SQL statement. This allows you to have controls bound to different tables through this query.
You can also place subforms on the main form that are bound to other tables than the main form.
You can also display the result of an expression in a TextBox by setting the ControlSource to an expression by starting with an equal sign
=DLookUp("Price", "TicketPriceTable", "TicketCode=" & Me!cboTicketCode.Value)
You can set the Format of a TextBox to MM\/yyyy or use the format function
s = Format$(Now, "MM\/yyyy")

MySQL GROUP BY with multiple parameters hiding zeros

I've read similar questions here on stackoverflow, but the OP's table structure is never quite the same as mine, so the answer doesn't work for me. The posts I've read are only trying to GROUP BY one column as opposed to two. I'm using MySQL, latest stable release.
Here's my table "reference":
id formatID referenceTime
1 1 2011-6-12 12:40
2 2 2011-6-12 1:04
3 4 2011-6-12 1:03
4 2 2011-6-12 15:20
5 3 2011-6-12 9:30
6 3 2011-6-12 2:55
7 5 2011-6-12 13:15
8 1 2011-6-12 12:32
(etc)
I want to create a query that show how many of each type of format occurred by hour of day. The point of this is to see what is the busiest time of day. I am trying to write a query that will create output that I can use for some simple graph web apps (Highcharts.js). I want it to look like this:
Timeofday Subgroup Count
12AM 1 2
12AM 2 6
12AM 3 7
12AM 4 2
12AM 5 0
1AM 1 3
1AM 2 3
1AM 3 0
1AM 4 0
1AM 5 1
(etc)
I'm using this query:
SELECT date_format(referenceTime,'%I %p') AS timeofday,
reference.referenceFormatID AS subgroup,
count(*) AS count
FROM reference
GROUP BY timeofday,subgroup ASC
However, the output skips "rows" where the count equals zero and so ends up looking like this:
Timeofday Subgroup Count
12AM 1 2
12AM 2 6
1AM 3 7
1AM 4 2
1AM 5 1
3AM 1 3
6AM 2 3
7AM 3 1
7AM 4 1
9AM 5 1
(etc)
I need those zeros to be able to create a properly formatted data series for my app.
The LEFT JOIN method where you put all the times into a second table isn't working for me because I am grouping by two different columns. Apparently, the LEFT JOIN criteria is satisfied as long as each hour shows up somewhere in the output table, but I need each hour to appear for each format.
Any suggestions?
You have two options, either create a lookup table with the possible hours in it, or use strange query involving the dual table and union to get the values that you are looking for.
In the first case, you would have a table with maybe a single field for the moment, let's just call it hours and the field is timeofday.
In the hours timeofday, you would have the following data:
timeofday
12AM
1AM
2AM
....
Then your query is as simple as
SELECT hours.timeofday,
reference.referenceFormatID AS subgroup,
count(reference.referenceFormatID) AS count
FROM hours
LEFT JOIN reference on date_format(referenceTime,'%I %p') = hours.timeofday
GROUP BY hours.timeofday,subgroup ASC
EDIT
To get all combinations, you would also need a formats table with all the possible formatIDs as was mentioned by rfausak. You could also do this with a distinct, but let's just assume that you have this table, let's call it formats. Again, this table could have a single column.
Part 1 is to get all the combinations:
SELECT hours.timeofday,
formats.ID
from hours
join formats
This is a Cartesian join that would merge all possible hours and format IDs.
Now we add in the LEFT JOIN
SELECT hours.timeofday,
formats.ID,
count(reference.subgroup)
FROM hours
JOIN formats
LEFT JOIN reference on date_format(referenceTime,'%I %p') = hours.timeofday
AND reference.subgroup = formats.ID
GROUP BY hours.timeofday,formats.ID ASC
If you try to do it using a DUAL table look up, you can use a method similar to generate days from date range