How to find new client? - php

I ran into one problem that I can not solve for 3 days already.
The problem is current, there is a database of two columns of date ("yyyy-mm") and the phone number is unique non-repeating. I want to find out how many new customers each month. Well, the formula is roughly current (the new client is the first month + the new client is the next month ....). If the customer meets the first month he is considered a new customer, then it is on the other month, he is missing a new customer.

try Something like this:
select year(f2.DateColumn) YearCol, month(f2.DateColumn) MonthCol, count(f2.PhoneNumber) NbNewPhone
from (
Select f1.*, row_number() over(partition by f1.PhoneNumber order by f1.DateColumn) rang
from yourTable f1
) f2
where f2.rang=1
group by year(f2.DateColumn), month(f2.DateColumn)
order by 1, 2
or if you column is not a date :
select f2.DateColumn, count(f2.PhoneNumber) NbNewPhone
from (
Select f1.*, row_number() over(partition by f1.PhoneNumber order by f1.DateColumn) rang
from yourTable f1
) f2
where f2.rang=1
group by f2.DateColumn
order by 1, 2

As per your example just below count is sufficient:
Select DateColumn, Count(PhoneNumber) from yourTable
Group by DateColumn
If Datecolumn is real date as yyyy-mm-dd with date datatype you can query as below:
Select year(datecolumn), month(datecolumn), count(PhoneNumber) from yourTable
group by year(datecolumn), month(datecolumn)

Related

MySQL query rows with defined date interval

I have no idea how to solve the following problem: I have several rows in my database with one timestamp per row. Now I would like to filter all rows for entries until the date interval for any two dates is bigger than 30 days. I have no defined date interval for specific dates, like between 12/01/2017 and 11/01/2017, that would be easy, even for me. All I know is that the timestamp interval from one row to the next row (query must be sorted by timestamp desc) must not be bigger than 30 days.
Please see my db at http://sqlfiddle.com/#!9/55a521/2
In this case the last entry shown should be the one with id 65404844. I would appreciate if you might give me a small hint for this.
Thank you very much!
You can use this query to build a filter.
SELECT
t.id,
from_unixtime(timestamp)
, IF(#pt < timestamp - 30*24*60*60, 1, 0) AS filter
, #pt := timestamp
FROM
t
, (SELECT #pt := MIN(timestamp) FROM t) v
ORDER BY timestamp
see it working live in an sqlfiddle
Important here is to order by timestamp. Then you initialize the #pt variable with the lowest value. Another important thing is to have the select clause in the right order.
First you compare the current record with the variable in the IF() function. Then you assign the current record to the variable. This way when the next row is evaluated, the variable still holds the value of the previous row in the IF() function.
To get the rows you want, use above query in a subquery to filter.
SELECT id, ts FROM (
SELECT
t.id,
from_unixtime(timestamp) as ts
, IF(#pt < timestamp - 30*24*60*60, 1, 0) AS filter
, #pt := timestamp
FROM
t
, (SELECT #pt := MIN(timestamp) FROM t) v
ORDER BY timestamp
) sq
WHERE sq.filter = 1
This filters out the rows that have a more than 30 days difference from the previous rows. (1st solution) - only works if the id column has consecutive values
SELECT t.id, t.timestamp, DATEDIFF(FROM_UNIXTIME(t1.timestamp), FROM_UNIXTIME(t.timestamp)) AS days_diff
FROM tbl t
LEFT JOIN tbl t1
ON t.id = t1.id + 1
HAVING days_diff <= 30
ORDER BY t.timestamp DESC;
This filters all the results that are within 30 days of each of the other entries.
SELECT *
FROM tbl t
WHERE EXISTS (
SELECT id
FROM tbl t1
WHERE DATEDIFF(FROM_UNIXTIME(t1.timestamp), FROM_UNIXTIME(t.timestamp)) < 30
AND t1.id <> t.id
)
ORDER BY t.timestamp desc;

Min value from Database in MySQL

Am trying to find the min value from past 30 days, in my table there is one entry for every day, am using this query
SELECT MIN(low), date, low
FROM historical_data
WHERE name = 'bitcoin'
ORDER BY STR_TO_DATE(date,'%d-%m-%Y') DESC
LIMIT 7
But this value not returing the correct value. The structure of my table is
Table structure
And table data which is store is like this
Table data style
Now what i need is to get the minimum low value. But my query not working it give me wrong value which even did not exist in table as well.
Updates:
Here is my updated Table Structure.
enter image description here
And here is my data in this table which look like this
enter image description here
Now if you look at the data, i want to check the name of token omisego and fatch the low value from past 7 days which will be from 2017-12-25 to 2017-12-19
and in this cast the low value is 9.67, but my current query and the query suggested by my some member did not brings the right answer.
Update 2:
http://rextester.com/TDBSV28042
Here it is, basically i have more then 1400 coins and token historical data, which means that there will me more then 1400 entries for same date like 2017-12-25 but having different name, total i have more then 650000 records. so every date have many entries with different names.
To get the lowest row per group you could use following
SELECT a.*
FROM historical_data a
LEFT JOIN historical_data b ON a.name = b.name
AND a.low > b.low
WHERE b.name IS NULL
AND DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
or
SELECT a.*
FROM historical_data a
JOIN (
SELECT name,MIN(low) low
FROM historical_data
GROUP BY name
) b USING(name,low)
WHERE DATE(a.date) >= '2017-12-19' AND DATE(a.date) <= '2017-12-25'
AND a.name = 'omisego'
DEMO
For last 30 day of 7 days or n days you could write above query as
SELECT a.*, DATE(a.`date`)
FROM historical_data2 a
LEFT JOIN historical_data2 b ON a.name = b.name
AND DATE(b.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(b.`date`) <= CURRENT_DATE()
AND a.low > b.low
WHERE b.name IS NULL
AND a.name = 'omisego'
AND DATE(a.`date`) >= CURRENT_DATE() - INTERVAL 30 DAY
AND DATE(a.`date`) <= CURRENT_DATE()
;
DEMO
But note it may return more than one records where low value is same, to choose 1 row among these you have specify another criteria to on different attribute
Consider grouping the same and running the clauses
SELECT name, date, MIN(low)
FROM historical_data
GROUP BY name
HAVING name = 'bitcoin'
AND STR_TO_DATE(date, '%M %d,%Y') > DATE_SUB(NOW(), INTERVAL 30 DAY);
Given the structure, the above query should get you your results.
// Try this code ..
SELECT MIN(`date`) AS date1,low
FROM historical_data
WHERE `date` BETWEEN now() - interval 1 month
AND now() ORDER by low ASC;

postgresql max(count(*)) - php

I have a problem in postgresql.
I have one cohorte (gathering of people) and i would like counting the persons in this cohorte.
Begin date : "2014-09-01", End date : "2014-11-30".
I have 5 persons between 09/01 and 09/22
I have 5 persons between 09/20 and 09/25
I have 5 persons between 09/26 and 10/05
I have 5 persons between 10/01 ans 11/30
I want to have the max of accommodation for each month between the begin date and the end date in SQL (or PHP). Expected max person count:
September(09) => 10
October(10) => 10
November(11) => 5
Find the maximum of simultaneously present persons on a single day for every month in a given period.
I suggest generate_series() to produce the series of days in your period. Then aggregate twice:
First to get a count for each day. A single day can be dealt with plain BETWEEN. Your ranges are obviously meant to be with include borders.
Second to get the maximum per month.
SELECT date_trunc('month', day)::date AS month, max(ct) AS max_ct
FROM (
SELECT g.day, count(*) AS ct
FROM cohorte
,generate_series('2014-09-01'::date -- first of Sept.
,'2014-11-30'::date -- last of Nov.
,'1 day'::interval) g(day)
WHERE g.day BETWEEN t_begin AND t_end
GROUP BY 1
) sub
GROUP BY 1
ORDER BY 1;
Returns:
month | max_ct
-----------+--------
2014-09-01 | 10
2014-10-01 | 10
2014-11-01 | 5
Use to_char() to prettify the month output.
SQL Fiddle .. is down ATM. Here is my test case (that you should have provided):
CREATE TEMP TABLE cohorte (
cohorte_id serial PRIMARY KEY
,person_id int NOT NULL
,t_begin date NOT NULL -- inclusive
,t_end date NOT NULL -- inclusive
);
INSERT INTO cohorte(person_id, t_begin, t_end)
SELECT g, '2014-09-01'::date, '2014-09-22'::date
FROM generate_series (1,5) g
UNION ALL
SELECT g+5, '2014-09-20', '2014-09-25'
FROM generate_series (1,5) g
UNION ALL
SELECT g+10, '2014-09-26', '2014-10-05'
FROM generate_series (1,5) g
UNION ALL
SELECT g+15, '2014-10-01', '2014-11-30'
FROM generate_series (1,5) g;
For more complex checks I'd suggest the OVERLAPS operator:
Find overlapping date ranges in PostgreSQL
For more complex scenarios I'd also consider range types:
Preventing adjacent/overlapping entries with EXCLUDE in PostgreSQL
can't you use window function?
I'd try something like this (I've not tested this code, just exposed my thoughts)
SELECT max(count) FROM (
SELECT count(*) OVER (PARTITION BY ???) as count
FROM contract
WHERE daterange(dateStart, dateEnd, '[]') && daterange('2014-09-01', '2014-10-01', '[)')
) as max
Here, my problem remains that I can't find a way to partition for each day of the interval. Maybe this is a wrong approach, but I would be interested by a solution based on windows.
edit: with this request, you have the max of simultaneous present, but over all the time, not only a given month
with presence as (
SELECT id, generate_series(begin_date, end_date, '1 day'::interval) AS date
FROM test
),
presents as (
SELECT count(*) OVER (PARTITION BY date) AS count
FROM presence
)
SELECT max(count) from presents;
Here we come, I think
Imagine your person table has 3 columnsĀ :
id
entrance_date
leaving_date
the request would look like
WITH presents as (
SELECT id,
daterange(entrance_date, leaving_date, '[]') * daterange('2014-09-01', '2014-11-30', '[]') as range
FROM person
WHERE daterange(entrance_date, leaving_date, '[]') && daterange('2014-09-01', '2014-11-30', '[]')
),
present_per_day as (
SELECT id,
generate_series(lower(range), upper(range), '1 day'::interval) AS date
FROM presents
),
count_per_day as (
SELECT count(*) OVER (PARTITION BY date) AS count,
date
FROM present_per_day
),
SELECT max(count) OVER (PARTITION BY date_part('year', date), date_part('month', date)) as max,
date_part('year', date),
date_part('month', date)
FROM count_per_day;
(I have to leave, I hope I'll have time to test it later)
In fact, #erwin solution is much much more easy and efficient than this one.

Extract the highest value of each day

I have a database table that is full of transactions transactionIDs and datetime fields.
As you would guess, the datetime field and transactionIDs are constantly increasing and the balance field is either increasing / staying the same / or decreasing.
I would like to extract the highest transactionID and its corresponding balance at the end of every day.
Thank you in advance for your time and assistance.
Sample Table Format:
transactionID|date (datetime)|amount|balance|
SELECT
t1.`date`,
t1.transactionID,
t2.balance
FROM
(
SELECT
`date`,
MAX(transactionID) AS `transactionID`
FROM
table
GROUP BY
DATE(`date`)
) t1
INNER JOIN
table t2
ON
t2.transactionID = t1.transactionID
ORDER BY
t1.`date`
I suggest you that insert unix_timestamp as your date field on your table.and use this query to fetch heighest transactionID :
$query = 'SELECT MAX (transactionID) FROM [ TABLE NAME ] WHERE [ DATE FIELD NAME ] BETWEEN' . strtotime("today 23:59"). ' AND ' . strtotime("today")
Try this:
SELECT balance FROM table WHERE table.created > TODAY() ORDER BY transactionID DESC LIMIT 1
table.created is the column containing the creation date of the record,
This query should give you the transactionID for just the current day. Do you need it for an interval of days? - in that case, the following query should do it
SELECT balance FROM
(SELECT transactionID, balance FROM table ORDER BY transactionID DESC)
GROUP BY DAYOFYEAR(table.created)

Unixtime & mysql

I have a field on my table which is called X, and I store unixtime(php -> time()).
My question is:
How can I list all the months from my DB, something like: 6.2009 8.2009 etc..
And my second question is:
How can I make a query to list all the informations based on a month and year on the same field X(i store unixtime), I know this doesn't work, but mabe you can understand it better: where date = '06.2009'
Any solutions?
List all months:
SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(X)) FROM MyTable;
Return all rows with a given year & month:
SELECT * FROM MyTable
WHERE EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(X)) = 200906;
Try this
SELECT FROM_UNIXTIME(X,'%m.%Y') FROM TABLE GROUP BY FROM_UNIXTIME(X,'%m.%Y')
SELECT * FROM TABLE WHERE FROM_UNIXTIME(X,'%m.%Y')='06.2009'
Bye
To answer your first question, you would do this with grouping:
SELECT FROM_UNIXTIME(timestamp_column, '%c.%Y') AS month, some_other_column FROM table_name GROUP BY month;
As for your second question, this depends on what you're trying to do. For example:
SELECT AVG(payment), SUM(*), FROM_UNIXTIME(timestamp_column, '%c.%Y') AS month, some_other_column FROM table_name WHERE timestamp_column BETWEEN UNIX_TIMESTAMP(200906) AND UNIX_TIMESTAMP(200907) - 1 GROUP BY month;
Would return the average of the payments and the number (sum) of rows for each group.
To get information ungrouped from a specific timeframe, reduce the query like so:
SELECT payment, some_other_column FROM table_name WHERE timestamp_column BETWEEN UNIX_TIMESTAMP(200906) AND UNIX_TIMESTAMP(200907) - 1;

Categories