I need to generate beginning balance for the selected month. for example, I'm having a list of pre-allocated serial numbers/ids/rows 1000 to 1999. In February I'm using 800 numbers (from id 1000-1799). Thus, my next months beginning balance would be 200.
In my DB I'm having three relevant columns: id, created_date and updated_date.
If I use only 50 numbers in March (1800-1849), then beginning balance for April is 150 (I already used up 850 of the pre-allocated 1000 ids). How to query the DB to fetch the number of remaining pre-allocated ids?
This example is based on the amount of information you provided and assumes you don't need to filter by user id or any other data, but that you do have a numeric row id.
SELECT (1000 - COUNT(*)) AS balance FROM table_name WHERE id BETWEEN 1000 AND 1999
If that is not the case, then please add the result of the
explain table_name command, where you substitute table_name with the actual name of the table.
Related
I've got a problem with this query:
$query="select *,max(revision) as maxrev
from oda
where name_company_app='$_SESSION[name_main]'
and year(date_emitted)='$_SESSION[year_ref]'
group by n_order
order by n_order DESC";
Inside DB I have a table (oda) where there are records with a order number (n_order) a revision of the order expressed with numbers (revsion=0-first|1-second|2-third eccetera...) with different date... the piont is, I sholud get an array with all orders of a certain company(name_company_app) showing only the last revision (from here the max()) of an order.
The point is that every new year the software starts counting n_orders from 1 so I have 300 orders of 2014 starting from 1 to 300 and 25 orders of 2015 starting from 1 to 25.. when I use "group by" it removes duplicates of n_orders selecting the max revision.
Result? I have first 25 numbers wrong (mixed by 2014 and 2015 depending the revision) and in total only 300 even they should be 325.
Any suggestion how may I change the query for showing all the data?
So I have a table that looks like this:
Person Product Date Quantity
1 A 1/11/2014 1
2 A 1/11/2014 2
1 A 1/20/2014 2
3 A 1/21/2014 1
3 B 1/21/2014 1
1 A 1/25/2014 1
I want to find the Count of Quantity where Product is A and Person has a Count > 1 WITHIN ANY SLIDING 30 DAY RANGE. Another key is that once two records meet the criteria, they should not add to the count again. For example, Person 1 will have a count of 3 for 1/11 and 1/20, but will not have a count of 3 for 1/20 and 1/25. Person 2 will have a count of 2. Person 3 will not show up in the results, because the second product is B. This query will run within a specific date range also (e.g, 1/1/2014 - 10/27/2014).
My product is written in MySQL and PHP and I would prefer to do this exclusively in MySQL, but this seems more like an OLAP problem. I greatly appreciate any guidance.
Another key is that once two records meet the criteria, they should not add to the count again.
This is not relational. In order for this to be meaningful, we have to define the order in which records are evaluated. While SQL does have ORDER BY, that's for display purposes only. It does not affect the order in which the query is computed. The order of evaluation is not meant to matter.
I do not believe this can be expressed as a SELECT query at all. If I am correct, that leaves you with plSQL or a non-SQL language.
If you're willing to drop this requirement (and perhaps implement it in post-processing, see below), this becomes doable. Start with a view of all the relevant date ranges:
CREATE VIEW date_ranges(
start_date, -- DATE
end_date -- DATE
) AS
SELECT DISTINCT date, DATE_ADD(date, INTERVAL 30 day)
FROM your_table;
Now, create a view of relevant counts:
CREATE VIEW product_counts(
person, -- INTEGER REFERENCES your_table(person)
count, -- INTEGER
start_date, -- DATE
end_date -- DATE
) AS
SELECT y.person,
sum(y.quantity),
r.start_date,
r.end_date
FROM date_ranges r
JOIN your_table y
ON y.date BETWEEN r.start_date AND r.end_date
GROUP BY y.person
HAVING sum(y.quantity) > 1;
For post-processing, you need to look at each row in the product_counts view and look up the purchase orders (rows of your_table) which correspond to it. Check whether you've seen any of those orders before (using a hash set), and if so, exclude them from consideration, reducing the count of the current item and possibly eliminating it entirely. This is best done in a procedural language other than SQL.
So I have a single table inside which I have a score system for points. It looks something along this line:
Columns:
ID Name Date Points
1 Peter 2014-07-15 5
2 John 2014-07-15 6
3 Bill 2014-07-15 3
and so on...
Everyday, the new results are being put into the table with the total amount of points acumulated, however in order to be able to get historic values, the results are put into new rows. So on the 2014-07-16, the table will look like this:
ID Name Date Points
1 Peter 2014-07-15 5
2 John 2014-07-15 6
3 Bill 2014-07-15 3
4 Peter 2014-07-16 11
5 John 2014-07-16 12
6 Bill 2014-07-16 3
However sometimes when a player doesn't take part for the whole day and doesn't get any points, he will still be added, but the points will remain the same (here this is shown by the case of Bill).
My question is how to count the number of each type of players (active - Peter and John ie when the points value changes from one date to another and inactive - Bill ie when the points value stays the same).
I have managed to get this query to only select players who do have the same value, but it's giving me the list of players rather than the count. Although I could potentialy be wrong with this query:
SELECT Points, name, COUNT(*)
FROM points
WHERE DATE(Date) = '2014-07-15' OR DATE(Date) = '2014-07-16'
GROUP BY Points
HAVING COUNT(*)>1
I'm not sure how to count the number of rows (could do a bypass trick with PHP getting the number of rows, but interested in SQL only) or how to invert it, to get a count of players who have a different score (again, could get total of rows and then subtract the above number, but not interested in that either - I'd prefer the SQL).
Regards and thanks in advance.
You are pretty close.
If you have at most one row per "player" per "date", you could do something like this:
SELECT SUM(IF(c.cnt_distinct_points<2,1,0)) AS cnt_inactive
, SUM(IF(c.cnt_distinct_points>1,1,0)) AS cnt_active
FROM ( SELECT p.name
, COUNT(DISTINCT p.points) AS cnt_distinct_points
FROM points p
WHERE DATE(p.Date) IN ('2014-07-15','2014-07-16')
GROUP BY p.name
) c
The inline view query (aliased as c) gets a count of the distinct number of "points" values for each player. We need to "group by" name, so we can get a distinct list of players, along with an indication whether the points value was different or not. If all of the non-NULL "points" values for a given player are the same, COUNT(DISTINCT ) will return a value of 1. Otherwise, we'll get a value larger than 1.
The outer query processes that list, collapsing all of the rows into a single row. The "trick" is to use expressions in the SELECT list that return 1 or 0, depending on whether the player is "inactive", and perform a SUM aggregate on that. Do the same thing, but a different expression to return a 1 if the player is "active".
If the count of distinct points for a player is 1, we'll essentially be adding 1 to cnt_inactive. Similarly, of the distinct points for a player is greater than 1, we'll be adding 1 to the cnt_active.
If this doesn't make sense, let me know if you have questions.
NOTE: Ideally, we'd avoid using the DATE() function around the p.Date column reference, so we could enable an appropriate index.
If the Date column is defined as (MySQL datatype) DATE, then the DATE() function is unnecessary. If the Date column is defined as (MySQL datatype) DATETIME or TIMESTAMP, we could use an equivalent predicate:
WHERE p.Date >= '2014-07-15' AND p.Date < '2014-07-16' + INTERVAL 1 DAY
That looks more complicated, but a predicate of that form is sargable (i.e. MySQL can use an index range scan to satisfy it, rather than having to look at every row in the table.)
For performance, we'd probably benefit from an index with leading columns of name and date
... ON points (`name`,`date`)
(MySQL may be able to avoid a "Using filesort" operation for the GROUP BY).
I would solve this problem by looking at the previous number of points and then doing a comparison:
select date(date), count(*) as NumActives;
from (select p.*,
(select p2.points
from points p2
where p2.name = p.name and p2.date < p.date
order by p2.date desc
limit 1
) as prev_points
from points p
) p
where prev_points is NULL or prev_points <> points;
Of course, you can add a where clause to get the count for any particular day.
I need to create an invoice number in format:
CONSTANT_STRING/%d/mm/yyyy
mm - Month (two digits)
yyyy - Year
Now, the %d is the number of the invoice in the specific month. Another words, this number is reseted every month.
Now I am checking in database what is the highest number in current month. Then after its incrementation I am saving the row.
I need the whole number to be unique. However, it sometimes happens that it is being duplicated (two users save in the same time).
Any suggestions?
Put a unique index on the field and catch the database error when trying to save the second instance. Also, defer getting the value until the last possible moment.
One solution is SELECT ... FOR UPDATE, which blocks the row until you update it, but can cause deadlocks with a serios multitasking application.
The best way is to fetch the number and increment it in a transaction and then start the work.
This way, the row is not locked for long.
Look into BEGIN WORK and COMMIT.
Use the primary key (preferably an INT) of the invoice table or assign a unique number to each invoice, e.g. via uniqid.
PS. If you are using uniqid, you can increase the uniqueness by setting more_entropy parameter to true.
set the id all in one query.
$query = 'INSERT INTO table (invoice_number) VALUES (CONCAT(\''.CONSTANT.'\', \'/\', (SELECT COUNT(*) + 1 AS current_id FROM table WHERE MONTH(entry_date) = \''.date('n').'\' AND YEAR(entry_date) = \''.date('Y').'\'), \'/\', \''.date('m/Y').'\'))';
I have about 10,000 products in the product table. I want to retrieve one of those items and display it in a section of a web page which stays the same for that particular day. Something like "Product of the day".
For example, if today I get product_id 100, then all of the visitors should be viewing this product item for today. Tomorrow it may fetch any random valid primary key, say, 1289 and visitors get 1289 product all day tomorrow.
Any ideas/suggestions?
Thanks for your help.
SELECT id
FROM products
ORDER BY
RAND(UNIX_TIMESTAMP(CURRENT_DATE()))
LIMIT 1
Maybe you can store the id of the item of the day in a table in the database?
How about create a cache file and invalidate it at midnight?
The benefit of this is you don't make unnecessary calls to your DB as you're only checking the timestamp on the cache file - only once per day do you make DB requests to populate a new cache file.
You don't need a CRON job for this:
if(date_of_file(potd_cache_file) != today){
potd_cache_file = generate_from_db();
}
load_file(potd_cache_file);
This will mean only the first visitor of the day to your website will trigger the regeneration, and every subsequent visitor will have a fast loading cache file served to them.
The idea is pretty simple,
Set a table up call ProductOfTheDay with a product ID and a date field
On the product of the day page when a user visits check the date field
If it is todays date then show the product
If it is not then randonly pick a new product and save it to the field.
Its not that complex of an operation.
SELECT id
FROM products
ORDER BY (id + RAND(UNIX_TIMESTAMP(CURRENT_DATE()))) MOD some_reasonable_value
LIMIT 1
You can start random number generators with a seed value.
Make the seed value be the day (21st) + month(10) + year(2009) so today's seed is 2041.
You will get the same random number all day, and tomorrow a different one. This is more how it works in .net. The random function takes a max and min value (this is your min and max ID values) then an optional seed value and returns a number. For the same seed number you get the same random number generated. It's possible if you change the max and min this can affect the number generated. You would have to look up how php works.
total = SELECT COUNT(id) FROM products;
day_product = SELECT id FROM products WHERE id = (UNIX_TIMESTAMP(CURRENT_DATE()) MOD total) LIMIT 1;
See also this question.