I am trying to make a query that checks the clients table and returns a count of users with a specific value for the last 30 days, 365 days and All Time.
The all time count is easy:
$stmt = $conn->prepare("SELECT count(id) AS count FROM clients WHERE referred = :refid");
$stmt->bindParam(':refid', $refid);
$stmt->execute();
$totalreferrals = $stmt->fetchAll();
Table:
id | signup | reffered |
----------------------------
2 | 2012-08-24 | 14 |
----------------------------
3 | 2011-10-13 | 14 |
I am not sure if I can combine the query using a UNION or if I should just make three different queries. Any help?
i think you want this in columns and not in rows if so here it is
SELECT COUNT(CASE WHEN DATEDIFF(CURDATE(),signup) <= 30 THEN id
ELSE NULL
END) AS Last30days ,
COUNT(CASE WHEN DATEDIFF(CURDATE(), signup) <= 365 THEN id
ELSE NULL
END) AS Last365Days ,
COUNT(*) AS Alltime
FROM Table1
WHERE reffered = 14
SQLFiddle http://sqlfiddle.com/#!2/6e6ce/2
Maybe this could solve the problem:
SELECT count(id) AS count FROM clients WHERE referred = :refid AND BETWEEN ADDDATE(NOW(), INTERVAL -1 MONTH) AND NOW();
SELECT count(id) AS count FROM clients WHERE referred = :refid AND BETWEEN ADDDATE(NOW(), INTERVAL -1 YEAR) AND NOW();
Related
I have a problem on a sql query. I need to take the last 30 days and then remove only the 4 results with the "voting" value greater
db structure
Id | time | voting
1 | unix time | 3
2 | unix time | 2
3 | unix time | 4
4 | unix time | 1
5 | unix time | 6
I would like to take me only the data of: 5-3-1-2
I have tried with
select a.*
from table a
inner join
( select votingng, max(time) as latest from table group by voting) v
on a.time = v.latest
and a.voting = v.voting
order by time desc limit
It sounds like you are trying to get the top 4 voting results in the past 30 days. Does either of these give you what you want?
SELECT a.*
FROM table a
WHERE a.time > UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 30 DAY))
ORDER BY a.voting DESC
LIMIT 4;
or
SELECT a.*
FROM table a
WHERE DATEDIFF( NOW(), FROM_UNIXTIME(a.time) ) <= 30
ORDER BY a.voting DESC
LIMIT 4;
I think this is what you want:
select v.*
from voting v
where timestamp >= unix_timestamp(date_sub(curdate(), interval 1 month)
order by voting desc
limit 4;
Hope this is what you are looking for:
Select *
From
Voting
Where
time Between CURDATE() And DATE_SUB(CURDATE(),INTERVAL 30 DAY)
Order By voting Desc
Limit 4
Try this if you are using teradata
SELECT * from table
qualify row_number () over(order by time desc)=1 ;
or
select * from
(select table.*, row_number () over(order by time desc) as RANK from table)
where RANK=1
Can anyone help me solve my complicated sql request?
I have an html page with a product list and to every item i want to join loading and sales information for last 4 months.
My desired result is:
Item1 - Month0 (12 in, 0 out), Month-1 (33 in, 36 out)......
Item2 - Month0 (10 in, 30 out), Month-1 (0 in, 66 out)......
My SQL Queries:
Products(simplified) in method "getProducts":
Select item_id, item_name
From Products
Loading
SELECT item_id, CONCAT(YEAR(`load_date`), MONTH(`load_date`)) AS YearMonth,SUM(load_qty) AS total,
FROM loading
GROUP BY YearMonth
WHERE item_id = ?
ORDER BY YearMonth DESC ', array($productId));
Sales
SELECT item_id, CONCAT(YEAR(`load_date`), MONTH(`load_date`)) AS YearMonth,SUM(load_qty) AS total,
FROM sales
GROUP BY YearMonth
WHERE item_id = ?
ORDER BY YearMonth DESC ', array($productId));
Then I got PHP file to call SQL method:
$products = $productManager->getProducts();
$this->data['portalProducts'] = $portalProducts;
And final HTML file with product list:
<?php foreach ($products as $product): ?>
<table>
<tr>
<td><?php echo date("Y - m", strtotime("now"))?></td> //current month
<td>//here goes current month load</td>
<td>//here goes current month sale</td>
</tr>
<tr>
<td><?php echo date("Y - m", strtotime("-1 month"))?></td> //last month
<td>//here goes last month load</td>
<td>//here goes last month sale</td>
</tr>
..............
</table>
Is it possible to combine all of the results from the above queries into one request and then display it as I mentioned in the beginning...
Thanks in advance.
You can combine your SQL queries as follows:
SELECT p.item_id, p.item_name, cal.year_month, COALESCE( q_in.total, 0 ) AS qty_in, COALESCE( q_out.total, 0 ) AS qty_out
FROM Products AS p
INNER JOIN
( SELECT CONCAT(YEAR(NOW()), MONTH(NOW())) AS `year_month`
UNION
SELECT CONCAT(YEAR(NOW() - INTERVAL 1 MONTH), MONTH(NOW() - INTERVAL 1 MONTH)) AS `year_month` ) AS `cal`
ON 1 = 1
LEFT JOIN
( SELECT `item_id`, CONCAT(YEAR(`load_date`), MONTH(`load_date`)) AS `year_month`, SUM(`load_qty`) AS `total`,
FROM loading
WHERE (`load_date` BETWEEN LAST_DAY(NOW() - INTERVAL 2 MONTH) + INTERVAL 1 DAY AND NOW())
GROUP BY `item_id`, YEAR(`load_date`), MONTH(`load_date`)) AS q_in
ON p.item_id = q_in.item_id AND cal.year_month = q_in.year_month
LEFT JOIN
( SELECT item_id, CONCAT(YEAR(`load_date`), MONTH(`load_date`)) AS `year_month`, SUM(`load_qty`) AS `total`,
FROM sales
WHERE (`load_date` BETWEEN LAST_DAY(NOW() - INTERVAL 2 MONTH) + INTERVAL 1 DAY AND NOW())
GROUP BY `item_id`, YEAR(`load_date`), MONTH(`load_date`)) AS q_out
ON p.item_id = q_out.item_id AND cal.year_month = q_out.year_month
ORDER BY p.item_id, p.item_name, q_in.year_month
Output example:
-------------------------------------------------------
| item_id | item_name | year_month | qty_in | qty_out |
-------------------------------------------------------
| 1 | blah | 201604 | 0 | 16 |
-------------------------------------------------------
| 1 | blah | 201605 | 12 | 16 |
-------------------------------------------------------
Explanation:
I have used "Calendar" sub-query to generate a list of months so that your output will always have a row for the current and the previous months even when total quantity for a given month is 0 in and 0 out:
( SELECT CONCAT(YEAR(NOW()), MONTH(NOW())) AS YearMonth
UNION
SELECT CONCAT(YEAR(NOW() - INTERVAL 1 MONTH), MONTH(NOW() - INTERVAL 1 MONTH)) AS YearMonth ) AS Cal
Afterwards I use a left join to join the queries for "loading" and "sales".
I have added a
WHERE (load_date BETWEEN LAST_DAY(NOW() - INTERVAL 2 MONTH) + INTERVAL 1 DAY AND NOW())
to each of the sub-queries to restrict the calculation to current and last month only. This is to improve performance.
Note: I have not tested the query in MySQL
This has me a stummped...
If I have a this MySQL table:
UserId | Commission | Date Of Commission
1 | 200.00 | 2014-02-12
1 | 50.00 | 2014-04-01
2 | 10.00 | 2014-04-05
and I would like to display the Total Commission for a specific user per week starting from his/her first record, and display 0 for that range if there's no record.
how would I go about it?
Sample Output
UserId | Date Range | Total Commission
1 | 02/10/14 - 02/16/14 | 200.00
1 | 02/17/14 - 02/23/14 | 0.00
...
1 | 03/31/14 - 04/06/14 | 50.00
I'm not a seasoned coder so any help will be much appreciated.
Thanks!
Edit:
I have tried this:
SELECT IFNULL(SUM(Commisssion),0) Total ,DATE_SUB(`DateOfCommission`,INTERVAL 7 DAY)
AS RangStart,DATE_SUB(`DateOfCommission`,INTERVAL 1 DAY) AS RangeEnd
FROM `comms` WHERE `UserId` = '$UserID' GROUP BY DATE(`DateOfCommission`) DESC
but it starts the week with whatever date the first record was entered..
This is very tricky to accomplish. Here is what I managed to do with small modifications it should work they way it needs to be. I have done it for userid = 1 and this could be done for other users as well.
In the query I have 2 lines
where a.Date BETWEEN (select min(date) from transactions where UserId = 1) AND NOW()
and
WHERE date BETWEEN (select min(date) from transactions where UserId = 1) AND NOW()
The query will try to generate the list of dates using the min() date of transaction for the user till today. Instead of now() this could be used as max() date of transaction for the user as well.
select
t1.date_range,
coalesce(SUM(t1.Commission+t2.Commission), 0) AS Commission
from
(
select
a.Date as date,
concat(
DATE_ADD(a.Date, INTERVAL(1-DAYOFWEEK(a.Date)) +1 DAY),
' - ',
DATE_ADD(a.Date, INTERVAL(7- DAYOFWEEK(a.Date)) +1 DAY)
) as date_range,
'0' as Commission
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) a
where a.Date BETWEEN (select min(date) from transactions where UserId = 1) AND NOW()
)t1
left join
(
SELECT date ,
coalesce(SUM(Commission), 0) AS Commission
FROM transactions
WHERE date BETWEEN (select min(date) from transactions where UserId = 1) AND NOW()
AND UserId = 1
GROUP BY date
)t2
on t2.date = t1.date
group by t1.date_range
order by t1.date_range asc
DEMO
So, this is sort of an algorithm you could use:
$Result = select distinct userid from table(this will fetch all userids from table)
while(There are rows in $Result)
{
$Userid = $Result['userid']
$StartDateRes = mysql_query(select Date, WEEKOFYEAR(Date) as week from table where userid = Userid order by date asc limit 1)
$StartDateRow = mysql_fetch_assoc($StartDateRes)
$StartDate = $StartDateRes['Date']
$StartWeekNumber = $StartDateRes['week']
$EndDateRes = mysql_query(select Date, WEEKOFYEAR(Date) as week from table where userid = Userid order by date desc limit 1)
$EndDateRow = mysql_fetch_assoc($EndDateRes)
$EndDate = $EndDateRes['Date']
$EndWeekNumber = $EndWeekRes['week']
for($i=$StartWeekNumber; $i<=$EndWeekNumber; $i++)
{
$StartDateOfWeek = FuncToFindStartDateOfWeek($i)
$EndDateOfWeek = FuncToFindEndDateOfWeek($i)
$Result2 = mysql_query(select sum(commission) as sum from table where date between StartDateOfWeek and EndDateOfWeek group by userid)
$Row2= mysql_fetch_assoc($Result2)
$Sum = $Row2['sum']
mysql_query("insert into OutputTable values($UserId, $StartDateOfWeek. '-'. $EndDateOfWeek ,$Sum");
}
}
SELECT UserId, COALESCE(SUM(Commission),0), YEARWEEK(DateOfCommission) AS TheWeek
GROUP BY UserId, TheWeek
ORDER BY UserId, TheWeek;
This will not print the nice date range, but should get you started in a SQL-only direction where the sum is broken down by the week of the year. I think you could take it from this point to add the nicer formatting of the Year/Week column. YEARWEEK() should give you pretty fast results.
The easiest way I can think of doing this as follows
Step 1: Get the date of the first record
"SELECT dateofcommission FROM comissionstable WHERE id='userid' ORDER BY dateofcommission ASC LIMIT 1"
The above query will return the first date of commission only
Step 2: Create a loop which starts from the date you got in Step 1 and continue the loop till the date is greater than or equal to today's date. Increment this date using PHP date function.
date('Y-m-d', strtotime($dateofcommission. ' + 7 days'));
Step 3: In this loop you can get the commission with-in the starting date and ending date. Starting date will be the date before adding 7 days and ending date will be the one after you have added 7 days.
SELECT SUM(commission) FROM commissiontable WHERE dateofcommission>= startingdate AND dateofcomission < endingdate AND id='userid'
The above logic should work. If you end up having some issues with this logic feel free to post in comments. I would be happy to help
The following is another solution
function getStartAndEndDate($week, $year) {
$time = strtotime("1 January $year", time());
$day = date('w', $time);
$time += ((7*$week)+1-$day)*24*3600;
$return[0] = date('Y-n-j', $time);
$time += 6*24*3600;
$return[1] = date('Y-n-j', $time);
return $return;
}
$query = mysqli_query($con, "SELECT userid, COALESCE( SUM( commission ) , 0 ) AS thecommission , YEARWEEK( doc ) AS TheWeek FROM commission GROUP BY userid, TheWeek ORDER BY userid, TheWeek");
while ($array = mysqli_fetch_array($query)) {
$test = $array['TheWeek'];
$store_array = getStartAndEndDate(substr($test,4,2), substr($test,0,4));
echo $array['userid']."-".$array['thecommission']."-".$store_array[0]."/".$store_array[1]."<br>";
}
I have a table
___________________________________________
id | user | Visitor | timestamp
___________________________________________
13 |username |abc | 2014-01-15 15:01:44
14 |username |abc | 2014-01-15 15:01:44
15 |username |abc | 2014-01-18 15:01:44
16 |username |abc | 2014-01-18 15:01:44
___________________________________________
I used QUERY to COUNT no of visitor of USER abc for last 7 days from TODAY.
SELECT DATE(`timestamp`) as `date`, COUNT(*) as `count`
FROM `table` WHERE (`timestamp` >= (NOW() - INTERVAL 7 DAY)) AND (`user` = 'username')
GROUP BY `date`;
It get following output:
______________________________
date | count
______________________________
2014-01-15 | 2
2014-01-18 | 2
But I need:
______________________________
date | count
______________________________
2014-01-15 | 2
2014-01-16 | 0 // Make 0 for the day which is not present
2014-01-17 | 0 // Make 0 for the day which is not present
2014-01-18 | 2
What will be query for this?
Use a subquer to create a table with all the days in the past week, then join that with your table:
SELECT `date`, IFNULL(COUNT(*), 0) as `count`
FROM (SELECT DATE(NOW()) AS `date`
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 1 DAY))
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 2 DAY))
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 3 DAY))
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 4 DAY))
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 5 DAY))
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 6 DAY))
UNION
SELECT DATE(DATE_SUB(NOW(), INTERVAL 7 DAY))) AS days
LEFT JOIN `table` ON DATE(`timestamp`) = `date`
WHERE (`timestamp` >= (NOW() - INTERVAL 7 DAY)) AND (`user` = 'username')
GROUP BY `date`;
It's a well-known problem about gap - and it has many answers on SO.
First, most obvious way - is to use table that will hold all dates consecutive (for current year as a sample) For example, let it be dates table with field record_date (it holds date) then your query will look like:
SELECT
DATE(`timestamp`) as `date`,
COUNT(`dates`.`id`) as `count`
FROM
`dates`
LEFT JOIN
`table`
ON `dates`.`record_date` = DATE(`table`.`timestamp`)
WHERE
(`timestamp` >= (NOW() - INTERVAL 7 DAY))
AND
(`user` = 'username')
GROUP BY
`dates`.`record_date`
-so you'll force returning zeros via LEFT JOIN.
There is another, more complex way, to achieve this with sequence generator query. Actually, there are no sequences in MySQL, but you can generate consecutive values from CROSS JOIN and then apply them to date selection. For example:
SELECT
DATE_ADD(CURDATE() - INTERVAL 1 WEEK, INTERVAL sequence.id DAY)
FROM
(SELECT
(two_1.id + two_2.id + two_4.id +
two_8.id + two_16.id) AS id
FROM
(SELECT 0 AS id UNION ALL SELECT 1 AS id) AS two_1
CROSS JOIN (SELECT 0 AS id UNION ALL SELECT 2 AS id) AS two_2
CROSS JOIN (SELECT 0 AS id UNION ALL SELECT 4 AS id) AS two_4
CROSS JOIN (SELECT 0 AS id UNION ALL SELECT 8 AS id) AS two_8
CROSS JOIN (SELECT 0 AS id UNION ALL SELECT 16 AS id) AS two_16
) AS sequence
WHERE
sequence.id<7
-will will produce dates for previous week, so you'll be able to use this instead of creating and filling temporary table like in first way. Good thing about this query is - that it's static, thus you'll not have to add another UNION part if you'll want to increase selection interval.
I have a table which keeps track of data from a game, here is an example of the table:
id | player_name | date | score | kills
1 | test1 | 2013-01-01 00:00:00 | 10000 | 200
2 | test1 | 2013-01-01 00:01:00 | 12000 | 300
I have a leaderboards for players, it ranks people who gain the most score/kills, etc. in a certain time period. At the moment I have only got it so that it ranks players in the previous 24 hours. I am doing this by selecting the first and last records in a specified time period and then subtracting them to get the difference.
This is my current query:
SELECT date, score FROM datapoints WHERE player_name = :player AND date = (SELECT MIN(date) FROM datapoints WHERE player_name = :player AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
UNION ALL
SELECT date, score FROM datapoints WHERE player_name = :player AND date = (SELECT MAX(date) FROM datapoints WHERE player_name = :player AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
After subtracting I use the PHP arsort() function to order them and then display them on the page.
However, I want to add another feature. I want to be able to see the on which day was the users best day for score/kills.
I have been thinking of how I could possibly do it and one was was using the above query but having a loop for each day and taking out the best day, however this probably isn't very efficient and I was wondering, if there was a better way of doing this?
Here is how you would get the score changes and kills that occur on any given calendar day:
select date(date) as thedate, max(score) - min(score) as DayScore,
max(kills) - min(kills) as DayKills
from datapoints dp
where player_name = :player
group by date(date);
To get the top day for scores, for instance, you would add an order by and limit clause like this:
order by DayScore desc
limit 1;