get data from same table in sql using join - sql

I have a table [dbo].[UserImages] where user uploads their photos after every 6 day, total 18 records for user 3. 9 records of day 1 and 9 records of day 6. There are 4 columns In this table
[Id, UserId, Image, Day]
Id UserId Image Day
1 3 3_20200408_1.png 1
2 3 3_20200408_2.png 1
3 3 3_20200408_3.png 1
4 3 3_20200408_4.png 1
5 3 3_20200408_5.png 1
6 3 3_20200408_6.png 1
7 3 3_20200408_7.png 1
8 3 3_20200408_8.png 1
9 3 3_20200408_9.png 1
10 3 3_20200410_9.png 6
11 3 3_20200410_2.png 6
12 3 3_20200410_3.png 6
13 3 3_20200410_4.png 6
14 3 3_20200410_5.png 6
15 3 3_20200410_6.png 6
16 3 3_20200410_7.png 6
17 3 3_20200410_8.png 6
18 3 3_20200410_9.png 6
I need something like that
ImgCount UserId ImageDay1 ImageDay6
1 3 3_20200408_1.png 3_20200408_1.png
2 3 3_20200408_2.png 3_20200408_2.png
3 3 3_20200408_3.png 3_20200408_3.png
4 3 3_20200408_4.png 3_20200408_4.png
5 3 3_20200408_5.png 3_20200408_5.png
6 3 3_20200408_6.png 3_20200408_6.png
7 3 3_20200408_7.png 3_20200408_7.png
8 3 3_20200408_8.png 3_20200408_8.png
9 3 3_20200408_9.png 3_20200408_9.png
What should I do for this

You can use row_number() and aggregation:
select
imgCount,
userId,
max(case when day = 1 then image end) ImageDay1,
max(case when day = 6 then image end) ImageDay6
from (
select t.*, row_number() over(partition by userId, day order by image) imgCount
from mytable t
where day in (1, 6)
) t
group by userId, imgCount
order by ImgCount
Demo on DB Fiddle:
ImgCount | userId | ImageDay1 | ImageDay6
:------- | -----: | :--------------- | :---------------
1 | 3 | 3_20200408_1.png | 3_20200410_1.png
2 | 3 | 3_20200408_2.png | 3_20200410_2.png
3 | 3 | 3_20200408_3.png | 3_20200410_3.png
4 | 3 | 3_20200408_4.png | 3_20200410_4.png
5 | 3 | 3_20200408_5.png | 3_20200410_5.png
6 | 3 | 3_20200408_6.png | 3_20200410_6.png
7 | 3 | 3_20200408_7.png | 3_20200410_7.png
8 | 3 | 3_20200408_8.png | 3_20200410_8.png
9 | 3 | 3_20200408_9.png | 3_20200410_9.png

Related

How to get columns when using buckets (width_bucket)

I would like to know which row were moved to a bucket.
SELECT
width_bucket(s.score, sl.mins, sl.maxs, 9) as buckets,
COUNT(*)
FROM scores s
CROSS JOIN scores_limits sl
GROUP BY 1
ORDER BY 1;
My actual return:
buckets | count
---------+-------
1 | 182
2 | 37
3 | 46
4 | 15
5 | 29
7 | 18
8 | 22
10 | 11
| 20
What I expect to return:
SELECT buckets FROM buckets_table [...] WHERE scores.id = 1;
How can I get, for example, the column 'id' of table scores?
I believe you can include the id in an array with array_agg. If I recreate your case with
create table test (id serial, score int);
insert into test(score) values (10),(9),(5),(4),(10),(2),(5),(7),(8),(10);
The data is
id | score
----+-------
1 | 10
2 | 9
3 | 5
4 | 4
5 | 10
6 | 2
7 | 5
8 | 7
9 | 8
10 | 10
(10 rows)
Using the following and aggregating the id with array_agg
SELECT
width_bucket(score, 0, 10, 11) as buckets,
COUNT(*) nr_ids,
array_agg(id) agg_ids
FROM test s
GROUP BY 1
ORDER BY 1;
You get
buckets | nr_ids | agg_ids
---------+--------+----------
3 | 1 | {6}
5 | 1 | {4}
6 | 2 | {3,7}
8 | 1 | {8}
9 | 1 | {9}
10 | 1 | {2}
12 | 3 | {1,5,10}

Select all the records in the first table that match each of the records in the second

I'm working with an Access database and have two tables:
ID_1
Number
Some other data
1
1
Data
2
2
Data
3
3
Data
4
4
Data
5
3
Data
6
1
Data
7
2
Data
8
3
Data
9
1
Data
10
1
Data
11
2
Data
12
3
Data
13
4
Data
14
1
Data
15
2
Data
16
3
Data
17
4
Data
18
3
Data
19
3
Data
ID_2
Number
Some other data
1
3
Data
2
1
Data
3
2
Data
4
3
Data
5
2
Data
As you see, both tables have duplicate data. I need a query that would select all the records in the first table that match each of the records in the second, they are related by Number field. It's also necessary that these records aren't repeated (that is, that the query doesn't repeat values when selecting). For the given example I should get this result:
ID
ID_1
Number
Some other data
1
3
3
Data
2
5
3
Data
3
8
3
Data
4
12
3
Data
5
16
3
Data
6
18
3
Data
7
19
3
Data
8
1
1
Data
9
6
1
Data
10
9
1
Data
11
10
1
Data
12
14
1
Data
13
2
2
Data
14
7
2
Data
15
11
2
Data
16
15
2
Data
I was thinking that maybe I could use Join, but I still don't know how; tried Where, but also didn't find a use for it. Could you please help me with that?
I don't see where you're generating your output ID field from - or where you're picking your Data field from so here's the best guess.
SELECT Table1.ID_1, Table1.Number, Table1.[Some other data]
FROM Table1
WHERE (Table1.Number In (SELECT Number From Table2))
ORDER BY Table1.Number, Table1.ID_1;
Looks like this:
MySql DB data structure
create table tbl1(ID_1 serial, Number int);
create table tbl2(ID_2 serial, Number int);
insert into tbl1(Number) values (1),(2),(3),(4),(3),(1),(2),(3),(1),(1),(2),(3),(4),(1),(2),(3),(4),(3),(3);
insert into tbl2(Number) values (3),(1),(2),(3),(2);
query (with s), needed to remove duplicates
the window function count(tbl1.Number) OVER(PARTITION BY Number) sorts the result for us by the count of matched numbers
the #rownum variable is needed to count rows
with s as (select distinct Number from tbl2),
f as (select ID_1,tbl1.Number from tbl1 left join s on
(tbl1.Number=s.Number) where s.Number is not null order by
count(tbl1.Number) OVER(PARTITION BY Number) desc)
select #rownum := #rownum + 1 AS ID,ID_1,Number from f, (SELECT #rownum := 0) r;
results
+------+------+--------+
| ID | ID_1 | Number |
+------+------+--------+
| 1 | 3 | 3 |
| 2 | 5 | 3 |
| 3 | 8 | 3 |
| 4 | 12 | 3 |
| 5 | 16 | 3 |
| 6 | 18 | 3 |
| 7 | 19 | 3 |
| 8 | 1 | 1 |
| 9 | 6 | 1 |
| 10 | 9 | 1 |
| 11 | 10 | 1 |
| 12 | 14 | 1 |
| 13 | 2 | 2 |
| 14 | 7 | 2 |
| 15 | 11 | 2 |
| 16 | 15 | 2 |
+------+------+--------+

RANK data by value in the column

I'd like to divide the data into separate groups (chunks) based on the value in the column. If the value increase above certain threshold, the value in the "group" should increase by 1.
This would be easy to achieve in MySQL, by doing CASE WHEN #val > 30 THEN #row_no + 1 ELSE #row_no END however I am using Amazon Redshift where this is not allowed.
Sample fiddle: http://sqlfiddle.com/#!15/00b3aa/6
Suggested output:
ID
Value
Group
1
11
1
2
11
1
3
22
1
4
11
1
5
35
2
6
11
2
7
11
2
8
11
2
9
66
3
10
11
3
A cumulative sum should do what you want:
SELECT *, sum((val>=30)::INTEGER) OVER (ORDER BY id BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM mydata ORDER BY id;
id | val | sum
----+-----+-----
1 | 11 | 0
2 | 11 | 0
3 | 22 | 0
4 | 11 | 0
5 | 35 | 1
6 | 11 | 1
7 | 11 | 1
8 | 11 | 1
9 | 66 | 2
10 | 11 | 2

Compare one value with other values within a group SQL Server

I have below table where column names are Item, Point and IsCorrect.
Item | Point | IsCorrect | Not actual column, just logic
-----+-------+-----------+--------------------
1 | 5 | 0 | 5 >= 6
1 | 8 | 0 | 8 >= 6
1 | 9 | 0 | 9 >= 6
1 | 6 | 1 | 6 >= 6
2 | 8 | 0 | 8 >= 7
2 | 7 | 1 | 7 >= 7
2 | 8 | 0 | 8 >= 7
2 | 9 | 0 | 9 >= 7
3 | 2 | 0 | 2 >= 9
3 | 5 | 0 | 5 >= 9
3 | 8 | 0 | 8 >= 9
3 | 9 | 1 | 9 >= 9
I want to first group by Item, get a Point value where IsCorrect = 1, compare it with other point values (as shown in 4th column). If all condition matched within a group, then select that item. I am expecting following result.
Item | Point | IsCorrect
-----+-------+----------
2 | 8 | 0
2 | 7 | 1
2 | 8 | 0
2 | 9 | 0
I want to use partition, not group by. Thank you so much for your help.
Window functions come to mind:
select t.*
from (select t.*,
max(case when iscorrect = 1 then point end) over (partition by item) as point_correct,
min(point) over (partition by item) as min_point
from t
) t
where min_point >= point_correct;
You could also do this with a subquery. Something like this:
select t.*
from t
where t.item in (select t2.item
from t t2
group by t2.item
having min(t2.point) >= min(case when t2.iscorrect then point end)
);
That is, for each item, compare the minimum point value to the "correct" point value.

SQL Query to select each row with max value per group

I'm very new to SQL and this one has me stumpted. Can you help me out with this query?
I have the following 2 tables:
TABLE 1: IssueTable
Id | RunId | Value
---
1 | 1 | 10
2 | 1 | 20
3 | 1 | 30
4 | 2 | 40
5 | 2 | 50
6 | 3 | 60
7 | 4 | 70
8 | 5 | 80
9 | 6 | 90
TABLE 2: RunTable
RunId | EnvironmentId
---
1 | 1
2 | 3
3 | 1
4 | 2
5 | 4
6 | 2
I need the IssueTable rows that represent the Max RunId grouped by the EnvironmentId in the RunTable. The result I would need from the tables is:
EXPECTED RESULT:
Id | RunId | Value | EnvironmentId
---
4 | 2 | 40 | 3
5 | 2 | 50 | 3
6 | 3 | 60 | 1
8 | 5 | 80 | 4
9 | 6 | 90 | 2
So only the rows with the most recent/highest RunId from the RunTable per EnvironmentId. For example, for the EnvironmentId of "1", I only want rows that contain a RunId of "3" because the most recent RunId on EnvironmentId "1" from the RunTable is "3". Likewise, the most recent run for EnvironementId "2" was RunId "6"
Use a subquery to get the max runid for each environmentid from the runtable. Join the obtained result to the issuetable and select the required columns.
select i.id, i.runid, i.value, r.environmentid
from (select environmentid, max(runid) maxrunid
from runtable
group by environmentid) r
join issuetable i on i.runid = r.maxrunid
order by i.runid, i.id
These days one can use the analytical functions like RANK, DENSE_RANK, ROW_NUMBER to generate some ranking of your records.
Window functions are part of the ANSI SQL:2003 standard.
And I've at least encountered them on TeraData, Oracle and SQL-Server.
select Id, RunId, Value, EnvironmentId
from (
select i.*, r.EnvironmentId,
dense_rank() over (partition by r.EnvironmentId order by r.RunId desc) as RN
from issuetable i
inner join runtable r on (i.RunId = r.RunId)
) Q
where RN = 1
order by Id;
The inner query would yield the following results :
Id RunId Value EnvironmentId RN
1 1 10 1 2
2 1 20 1 2
3 1 30 1 2
4 2 40 3 1
5 2 50 3 1
6 3 60 1 1
7 4 70 2 2
8 5 80 4 1
9 6 90 2 1