I have the following table below and I am trying to find each IID that has at least 2 or more same IID's and find the average of the stats. The MySQL statement is as follows:
select count(distinct IID) as counted from rate; but I get one field and it states a number of 15, the table is very small and only has 20 tuples. I am stuck and can't go any further than this.
UID| IID | stats
-----------------
1 | 1 | 3
1 | 1 | 4
1 | 3 | 1
2 | 3 | 1
2 | 3 | 1
2 | 1 | 3
2 | 2 | 4
The result I would like to see is
grouped by IID's if there is two or more and an average of stats. I have a feeling I have to group by IID and sum the stats and divide by amount of count.
IID | stats
-----------------
1 | 3.5
3 | 1.5
If you really want an average then just use avg(stats). I couldn't see how to make the numbers match with your output so I thought perhaps you wanted a different divisor.
select sum(stats) / (count(distinct UID) * 1e) /* cast to float */
from rate
group by IID
having count(*) > 1
That is most likely correct. Your statement counts the number of distinct values in that column. For your case, you should use group by and having.
why don't you use group_by(IID) that will group your data according to IID then use where clause in it.
The following query will return the average of stats for each iid that has more than one row:
select iid, avg(stats)
from table t
group by iid
having count(*) > 1;
This seems like a reasonable result, but the values would be:
1 3.33
3 1
I am not sure what calculation you have in mind for the results in your question.
Related
Following is my scenario
I have tables named
Products
id | name | count | Price
-------------------------
1 | meat | 1 | 10
Users
id | name | balance
-----------------
1 | Tim | 10
2 | Joe | 10
Work flow
select products if count >= 1,
reduce user's balance and count = count - 1
if no_balance or count < 1 throw error
Let's say if both users placing an order for 1 product at exact same time, products table count updates to -1, means query executes for both users.
Products
id | name | count | Price
-------------------------
1 | meat | -1 | 10
During placeing of an order,I have used the below query to select matching products
Select * from products where count >= 1 and price >= 10
Also, if users place orders with even little time difference, the expecting output gathered.
Is there any solution to this ?
You should consider use lock for each row, for example.
Select * from products where count >= 1 and price >= 10 FOR UPDATE.
But in your scenario, I advice you use Redis to do that.
How to design a second kill system for online shop
I am not very good at sql but I am getting there. I have searched stackoverflow but I can't seem to find the solution and I hope someone out there can help me. I have a table (users) with data like the following. The book_id column is a key to another table that contains a book the user is subscribed to.
|--------|---------------------|------------------|
| id | book_id | name |
|--------|---------------------|------------------|
| 1 | 1 | jim |
| 2 | 1 | joyce |
| 3 | 1 | mike |
| 4 | 1 | eleven |
| 5 | 2 | max |
| 6 | 2 | dustin |
| 7 | 2 | lucas |
|--------|---------------------|------------------|
I have a function in my PHP code that returns two random users from a specific book id (either 1 or 2). Query one returns the result in column 1 and result two returns the results in column 2 like:
|---------------------|------------------|
| 1 | 2 |
|---------------------|------------------|
| jim | max |
| joyce | dustin |
|---------------------|------------------|
I have achieved this by running two separate queries as seen below. I want to know if it's possible to achieve this functionality with one query and how.
$random_users_with_book_id_1 = SELECT name FROM users WHERE book_id=1 LIMIT 2
$random_users_with_book_id_2 = SELECT name FROM users WHERE book_id=2 LIMIT 2
Again, I apologise if it's too specific. The query below has been closest to what I was trying to achieve.:
SELECT a.name AS book_id_1, b.name AS book_id_2
FROM users a, users b
WHERE a.book_id=1 AND b.book_id = 2
LIMIT 2
EDIT: I have created a fiddle to play around with his. I appreciate any help! Thank you!! http://sqlfiddle.com/#!9/7fcbca/1
It is easy actually :)
you can use UNION like this:
SELECT * FROM (
(SELECT * FROM user WHERE n_id=1 LIMIT 2)
UNION
(SELECT * FROM user WHERE n_id=2 LIMIT 2))
collection;
if you read this article about the documentation you can use the () to group the individual queries and the apply the union in the middle. Without the parenthesis it would still LIMIT 2 and show only the two first. Ref. "To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT:"
If you want to combine the queries in MySQL, you can just use parentheses:
(SELECT name
FROM users
WHERE n_id = 1
LIMIT 2
) UNION ALL
(SELECT name
FROM users
WHERE n_id = 2
LIMIT 2
);
First, only use UNION if you specifically want to incur the overhead of removing duplicates. Otherwise, use UNION ALL.
Second, this does not return random rows. This returns arbitrary rows. In many cases, this might be two rows near the beginning of the data. If you want random rows, then use ORDER BY rand():
(SELECT name
FROM users
WHERE n_id = 1
ORDER by rand()
LIMIT 2
) UNION ALL
(SELECT name
FROM users
WHERE n_id = 2
ORDER BY rand()
LIMIT 2
);
There are other methods that are more efficient, but this should be fine for up to a few thousand rows.
I have a table that list system licences, multiple licences for each system (the expired ones and existing ones). I've only posted two columns in this question as they're the only important ones.
| id | systemid |
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 3 |
| 6 | 3 |
I need to get the rows with the id of 2, 4 and 6.
I need to collect 1 record for each systemid and it has to be the earliest (youngest) record, so in this case, the record with the highest id. I've been exploring GROUP BY, ORDER BY and LIMIT but I'm not producing the result I'm after. How do you collect one record for each individual value in one column and make sure it's the record with the highest id?
I KNOW this is wrong, but it's what I'm currently starring at:
SELECT * FROM licences GROUP BY systemid ORDER BY id DESC LIMIT 1
SELECT max(id), systemid FROM table GROUP BY systemid
Note that with a GROUP BY, all columns you select must either be in the GROUP BY clause or wrapped in an aggregating function, like max, min, sum, or average.
This will grab the highest id per systemid.
SELECT MAX(id), systemid
FROM ...
GROUP BY systemid
Let`s say I have the following table
+----+-------+
| Id | Value |
+----+-------+
| 1 | 2.0 |
| 2 | 8.0 |
| 3 | 3.0 |
| 4 | 9.0 |
| 5 | 1.0 |
| 6 | 4.0 |
| 7 | 2.5 |
| 8 | 6.5 |
+----+-------+
I want to plot these values, but since my real table has thousands of values, I thought about getting and average for each X rows. Is there any way for me to do so for, ie, each 2 or 4 rows, like below:
2
+-----+------+
| 1-2 | 5.0 |
| 3-4 | 6.0 |
| 5-6 | 2.5 |
| 7-8 | 4.5 |
+-----+------+
4
+-----+------+
| 1-4 | 5.5 |
| 5-8 | 3.5 |
+-----+------+
Also, is there any way to make this X value dynamic, based on the total number of rows in my table? Something like, if I have 1000 rows, the average will be calculated based on each 200 rows (1000/5), but if I have 20, calculate it based on each 4 rows (20/5).
I know how to do that programmatically, but is there any way to do so using pure SQL?
EDIT: I need it to work on mysql.
Depending on your DBMS, something like this will work:
SELECT
ChunkStart = Min(Id),
ChunkEnd = Max(Id),
Value = Avg(Value)
FROM
(
SELECT
Chunk = NTILE(5) OVER (ORDER BY Id),
*
FROM
YourTable
) AS T
GROUP BY
Chunk
ORDER BY
ChunkStart;
This creates 5 groups or chunks no matter how many rows there are, as you requested.
If you have no windowing functions you can fake it:
SELECT
ChunkStart = Min(Id),
ChunkEnd = Max(Id),
Value = Avg(Value)
FROM
YourTable
GROUP BY
(Id - 1) / (((SELECT Count(*) FROM YourTable) + 4) / 5)
;
I made some assumptions here such as Id beginning with 1 and there being no gaps, and that you would want the last group too small instead of too big if things didn't divide evenly. I also assumed integer division would result as in Ms SQL Server.
You can use modulos operator to act on every Nth row of the table. This example would get the average value for every 10th row:
select avg(Value) from some_table where id % 10 = 0;
You could then do a count of the rows in the table, apply some factor to that, and use that value as a dynamic interval:
select avg(Value) from some_table where id % (select round(count(*)/1000) from some_table) = 0;
You'll need to figure out the best interval based on the actual number of rows you have in the table of course.
EDIT:
Rereading you post I realize this is getting an average of every Nth row, and not each sequential N rows. I'm not sure if this would suffice, or if you specifically need sequential averages.
Look at the NTILE function (as in quartile, quintile, decile, percentile). You can use it to split your data evenly into a number of buckets - in your case it seems you would like five.
Then you can use AVG to calculate an average for each bucket.
NTILE is in SQL-99 so most DBMSes should have it.
You can try that
CREATE TABLE #YourTable
(
ID int
,[Value] float
)
INSERT #YourTable (ID, [Value]) VALUES
(1,2.0)
,(2,8.0)
,(3,3.0)
,(4,9.0)
,(5,1.0)
,(6,4.0)
,(7,2.5)
,(8,6.5)
SELECT
ID = MIN(ID) + '-' + MAX(ID)
,[Value] = AVG([Value])
FROM
(
SELECT
GRP = ((ROW_NUMBER() OVER(ORDER BY ID) -1) / 2) + 1
,ID = CONVERT(VARCHAR(10), ID)
,[Value]
FROM
#YourTable
) GrpTable
GROUP BY
GRP
DROP TABLE #YourTable
Hits Table:
hid | lid | IP
1 | 1 | 123.123.123.123
2 | 1 | 123.123.123.123
3 | 2 | 123.123.123.123
4 | 2 | 123.123.123.123
5 | 2 | 123.123.123.124
6 | 2 | 123.123.123.124
7 | 3 | 123.123.123.124
8 | 3 | 123.123.123.124
9 | 3 | 123.123.123.124
As you can see, there following are the unique hits for the various lid:
lid 1: 1 unique hit
lid 2: 2 unique hits
lid 3: 1 unique hit
So basically, I need a query that will return the following:
lid | uhits |
1 | 1 |
2 | 2 |
3 | 1 |
Anybody know how to get that?
Select lid, count(distinct IP) as uhits
from hits
group by lid
Until you start getting into really complicated queries, SQL is made so it reads quite like a natural sentence. So first, if you can describe exactly what you want out of your query, you've already half written the SQL.
In this case, you can describe your problem like:
Get lid and the aggregate count of unique IP from my table for each lid.
The only thing that remains is to translate this, using SQL keywords. The important ones here being:
get -> SELECT
count -> COUNT
unique -> DISTINCT
aggregate..for each <field> -> SELECT <aggregate function>..GROUP BY <field>
So, your sentence above starts to look like:
SELECT lid and the aggregate COUNT of DISTINCT IP FROM my table GROUP BY lid.
Removing unnecessary words, and cleaning it up to use SQL syntax leaves the final query:
SELECT hits.lid, COUNT(DISTINCT hits.IP) AS uhits
FROM hits
GROUP BY hits.lid
SELECT lid, COUNT(DISTINCT IP)
FROM hits
GROUP BY lid
You need use group by:
SELECT lid, count(*)
FROM Table
GROUP BY lid