Group MySQL values from table - mysql

I'm sure this is possible I don't know where to start.
I have a table with 2000 values they are on the range from 0 to 100.
I want to query the table to get the different groups of values.
i.e. I have those values 5, 10 , 5 , 2 , 2, 0, 1, 1, 1, 1, 1, 10, 2
I want an output like this:
Value - Number_of_times
0 1
1 5
2 3
5 2
10 2

You need to group your results by your field, and take the COUNT() of each group:
SELECT myfield, COUNT(*) as number_of_times
FROM mytable
GROUP BY myfield

Related

SQL Query, get all ids that do not have a given status value

I have a table called statuses shown below. Every time a user logs in a row is added. A status is added. I need to write a query that gives me all IDs one time that have never been 1, 6 or 8.
id
status
1
1
1
6
1
8
1
1
2
1
2
6
2
8
2
0
3
0
3
0
3
0
3
0
I wrote a query:
SELECT DISTINCT(id) FROM statuses WHERE status NOT IN (1, 6, 8)
Unfortunately this gives me ID 2 and 3, but I don't want ID 2 to be selected because they have statuses 1, 6, and 8.
Thanks for your help!
You can group by id and set the condition in the HAVING clause:
SELECT id
FROM statuses
GROUP BY id
HAVING SUM(status IN (1, 6, 8)) = 0
Or:
SELECT DISTINCT id
FROM statuses
WHERE id NOT IN (SELECT id FROM statuses WHERE status IN (1, 6, 8))
See the demo.

Selecting sum of three consecutive values in a same row in the table in MYSQL

plz refer the table to provide the sql query to get result like that.
id value
1 10
2 15
3 30
4 10
5 11
6 12
Desired output:
id value
1 55
2 33
http://sqlfiddle.com/#!9/21cbc8
Divide id by 3, round it up, group it (with a sum):
SELECT
ceiling(id / 3) AS NewID,
sum(Value) AS SumValue
FROM MyTable
GROUP BY ceiling(id / 3)
With a variable:
SET #GroupVar = 3; -- Set this number to whatever you want to group by
SELECT
ceiling(id / #GroupVar) AS NewID,
sum(Value) AS SumValue
FROM MyTable
GROUP BY ceiling(id / #GroupVar);

How to limit results of SQLite per specific group of results?

I have the following problem at work. I have a large table with different columns and few 100 000s of rows. I'll only post the ones im interested in.
Assume the following data set
Device ID, Feature Id, Feature Status
1, 1, 0
1, 2, 0
1, 3, 1
1, 4, 1
1, 5, 1
2, 1, 1
2, 2, 0
2, 3, 0
2, 4, 1
2, 5, 0
3, 1, 1
3, 2, 1
3, 3, 1
3, 4, 1
3, 5, 1
4, 1, 0
4, 2, 0
4, 3, 1
4, 4, 0
4, 5, 0
I need to select rows with Feature Status = 1 but only the first 2 from each Device Id.
The results of the query should be:
1,3,1
1,4,1
2,1,1
2,4,1
3,1,1
3,2,1
4,3,1
I tried something like this:
SELECT brdsurfid,featureidx,FeatStatus FROM Features F1 WHERE FeatStatus = 1 AND
(SELECT COUNT(*) FROM Features F2
WHERE F2.FeatureIdx <= F1.FeatureIdx AND F2.FeatStatus = 1) < 2
ORDER BY BrdSurfId,FeatureIdx;
which I found in another response but it didnt quite work.
I know I need to use a mix of LIMIT or COunt(*) and some nested selects but I can't figure it out. Thanks
This probably not a very efficient way to do this, but I don't think there is a better solution for sqlite (that involves a single query):
SELECT *
FROM t t0
WHERE FeatureStatus AND
(SELECT count(*)
FROM t t1
WHERE t0.DeviceID=t1.DeviceID
AND FeatureStatus
AND t1.FeatureId<t0.FeatureId
)<2;
I assume that the table is called t. The idea is to find all features where the status is 1 and then for each feature to count the previous features with that status for the same product. If that count is more than 2, then reject the row.
Not sure if this will work with sqlite but for what its worth...
;with result as
(
SELECT
brdsurfid,
featureidx,
FeatStatus ,
ROW_NUMBER() OVER(PARTITION BY brdsurfid ORDER BY fieldWhatever) AS 'someName1',
ROW_NUMBER() OVER(PARTITION BY featureidx ORDER BY fieldWhatever) AS 'someName2',
ROW_NUMBER() OVER(PARTITION BY FeatStatus ORDER BY fieldWhatever) AS 'someName3'
FROM
Features
)
SELECT *
FROM
result
WHERE
FeatStatus = 1 AND
someName1 <= 2 AND
someName2 <= 2 AND
someName3 <= 2

Count up on a positive change, and down on a negative change

I have a column that changes values.
I want to count by adding at each change up and subtracting at each change down. Assuming x[] are my values, Delta is the sign of change in x's elements, and y[] is my targeted results or counts.
We count up until the next delta -1 at which we start counting down, then we resume counting up when delta changes back to +1. In summary we add normally until we have a delta of -1 at that time we start subtracting, then resume adding up at the next +1 delta.
x: 1, 3, 4, 4, 4, 5, 5, 3, 3, 4, 5, 5, 6, 5, 4, 4, 4, 3, 4, 5, 6, 7, 8
Delta: 0, 1, 1, 0, 0, 1, 0, -1, 0, 1, 1, 0, 1, -1, -1, 0, 0, -1, 1, 1, 1, 1, 1
y: 1, 2, 3, 4, 5, 6, 7, 6, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 5, 6, 7, 8, 9
The length of my array is in the millions of rows, and efficiency is important. Not sure if such operation should be done in SQL or whether I would be better off retrieving the data from the database and performing such calculation outside.
You could use this query in SQL-Server, presuming a PK-column for the ordering:
WITH CTE AS
(
SELECT t.ID, t.Value,
LastValue = Prev.Value,
Delta = CASE WHEN Prev.Value IS NULL
OR t.Value > Prev.Value THEN 1
WHEN t.Value = Prev.Value THEN 0
WHEN t.Value < Prev.Value THEN -1 END
FROM dbo.TableName t
OUTER APPLY (SELECT TOP 1 t2.ID, t2.Value
FROM dbo.TableName t2
WHERE t2.ID < t.ID
ORDER BY t2.ID DESC) Prev
)
, Changes AS
(
SELECT CTE.ID, CTE.Value, CTE.LastValue, CTE.Delta,
Change = CASE WHEN CTE.Delta <> 0 THEN CTE.Delta
ELSE (SELECT TOP 1 CTE2.Delta
FROM CTE CTE2
WHERE CTE2.ID < CTE.ID
AND CTE2.Delta <> 0
ORDER BY CTE2.ID DESC) END
FROM CTE
)
SELECT SUM(Change) FROM Changes c
The result is 9 as expected:
complete result set
only Sum
The OUTER APPLY links the current with the previous record, the previous record is the one with the highest ID < current.ID. It works similar to a LEFT OUTER JOIN.
The main challenge was the sub-query in the last CTE. That is necessary to find the last delta that is <> 0 to determine if the current delta is positive or negative.
You can also use LAG and SUM with OVER (Assuming you have SQL Server 2012 or above) like this.
Sample Data
DECLARE #Table1 TABLE (ID int identity(1,1), [x] int);
INSERT INTO #Table1([x])
VALUES (1),(3),(4),(4),(4),(5),(5),(3),(3),(4),(5),(5),(6),(5),(4),(4),(4),(3),(4),(5),(6),(7),(8);
Query
;WITH T1 as
(
SELECT ID,x,ISNULL(LAG(x) OVER(ORDER BY ID ASC),x - 1) as PrevVal
FROM #Table1
), T2 as
(
SELECT ID,x,PrevVal,CASE WHEN x > PrevVal THEN 1 WHEN x < PrevVal THEN -1 ELSE 0 END as delta
FROM T1
)
SELECT ID,x,SUM(COALESCE(NULLIF(T2.delta,0),TI.delta,0))OVER(ORDER BY ID) as Ordered
FROM T2 OUTER APPLY (SELECT TOP 1 delta from T2 TI WHERE TI.ID < T2.ID AND TI.x = T2.x AND TI.delta <> 0 ORDER BY ID DESC) as TI
ORDER BY ID
Output
ID x Ordered
1 1 1
2 3 2
3 4 3
4 4 4
5 4 5
6 5 6
7 5 7
8 3 6
9 3 5
10 4 6
11 5 7
12 5 8
13 6 9
14 5 8
15 4 7
16 4 6
17 4 5
18 3 4
19 4 5
20 5 6
21 6 7
22 7 8
23 8 9
You use sql-server and mysql tag. If this can be done within SQL-Server you should have a look on the OVER-clause: https://msdn.microsoft.com/en-us/library/ms189461.aspx
Assuming there's an ordering criteria it is possible to state a ROW-clause and use the value of a preceeding row. Many SQL-functions allow the usage of OVER.
You could define a computed column which does the calculation on insert...
Good luck!

How to query rows that are not in a table?

First of all, I don't think my title is good, but I couldn't think of a better one. Please feel free to change it.
I have a table that keeps record of a pair of rows.
The following is a sample table structure.
table History
user_id row_1 row_2
2 1 2
2 1 3
table Rows
row_id
1
2
3
4
5
6
I would like to query to get only a pair of rows that are not in the 'History' table.
so..I like to get the following result.
row pairs:
1,4
1,5
1,6
2,3
2,4
2,5
2,6
and so on
Can I do it with one query?
Just added:
I just made a query that works, but I am not sure about the performance.
select r1.row_id, r2.row_id from rows as r1 cross join rows as r2
where r1.row_id!=r2.row_id and ( r1.row_id + r2.row_id) not in (select row_1 + row_2 from history)
order by r1.row_id desc
Would it be super slow?
Something like this. You haven't made the correlations clear between the fields but this should be easy to adapt.
select h.row_id r1, r.row_id r2
from rows h
cross join rows r
left join history h2 on h2.row_1=h.row_id and h2.row_2=r.row_id
where h2.row_1 is null
The CROSS JOIN produces all the possible combinations of row_id x row_id
THE LEFT JOIN attempts to find the combination in the history table
The WHERE clause picks out where the combination is not found
I think this might work:
SELECT DISTINCT
CASE WHEN r1.row_id < r2.row_id THEN r1.row_id ELSE r2.row_id END AS row_id_1,
CASE WHEN r1.row_id < r2.row_id THEN r2.row_id ELSE r1.row_id END AS row_id_2
FROM Rows AS r1
INNER JOIN Rows AS r2 /* ON r1.row_id <> r2.row_id */
WHERE (r1.row_id, r2.row_id) NOT IN (
SELECT row_1, row_2
FROM history
UNION
SELECT row_2, row_1
FROM history
)
ORDER BY 1, 2
Returns:
1, 1
1, 4
1, 5
1, 6
2, 2
2, 3
2, 4
2, 5
2, 6
3, 3
3, 4
3, 5
3, 6
4, 4
4, 5
4, 6
5, 5
5, 6
6, 6
This query will be super slow.