H2 SQL Sequence count with duplicate values - sql

I have a table of IDs, with some duplicates and I need to create a sequence based on the IDs. I'm trying to achieve the following.
[ROW] [ID] [SEQID]
1 11 1
2 11 2
3 12 1
4 13 1
5 13 2
I'm using an old version of the H2 DB which doesn't have use of windows functions so I have todo this using straight SQL. I have tried joining the table on itself but I'm not getting the result I want as the duplicate values cause issues, any ideas? I have unique identifier in row number, but not sure how to use this to achieve what I want?
SELECT A.ID, COUNT(*) FROM TABLE A
JOIN TABLE B
ON A.ID = B.ID
WHERE A.ID >= B.ID
GROUP BY A.ID;

Use a subquery that counts the seqid:
select
t.row, t.id,
(select count(*) from tablename where id = t.id and row <= t.row) seqid
from tablename t
It's not as efficient as window functions but it does what you expect.
See the demo (for MySql but it's standard SQL).
Results:
| row | id | seqid |
| --- | --- | ----- |
| 1 | 11 | 1 |
| 2 | 11 | 2 |
| 3 | 12 | 1 |
| 4 | 13 | 1 |
| 5 | 13 | 2 |

Related

Selecting the first row of group with additional group by columns

Say I have a table with the following results:
How is it possible for me to select such that I only want distinct parent_ids with the min result of object0_behaviour?
Expected output:
parent_id | id | object0_behaviour | type
------------------------------------------
1 | 1 | 5 | IP
2 | 3 | 5 | IP
3 | 5 | 7 | ID
4 | 6 | 7 | ID
5 | 8 | 5 | IP
6 | 18 | 7 | ID
7 | 10 | 7 | ID
8 | 9 | 5 | IP
I have tried:
SELECT parent_id, min(object0_behaviour) FROM table GROUP BY parent_id
It works, however if I wanted the other 2 additional columns, I am required to add into GROUP BY clause and things go back to square one.
I saw examples with R : Select the first row by group
Similar output from what I need, but I can't seem to convert it into SQL
You can try using row_number() window function
select * from
(
select *, row_number() over(partition by parent_id order by object0_behaviour) as rn
from tablename
)A where rn=1
select * from table
join (
SELECT parent_id, min(object0_behaviour) object0_behaviour
FROM table GROUP BY parent_id
) grouped
on grouped.parent_id = table.parent_id
and grouped.object0_behaviour = table.object0_behaviour

Get N results for each group without using join

can I solve this without using join? there are so many data in this table, I want to do it more efficiently.
one of my idea is get ID list by using group_concat subquery, but it doesn't work well with IN clause.
SELECT * FROM table WHERE id IN (group_concat subquery)
May I get your advice?
data
ID SERVER_ID ...
--------------------
1 1 ...
2 1
3 1
4 2
5 2
6 2
7 3
8 3
9 3
10 3
...
expected result with limit 2 per each group:
ID SERVER_ID ...
--------------------
1 1 ...
2 1
4 2
5 2
7 3
8 3
You can try the following using row_number, this solution will work for postgreSQL, MySQL 8.0, Oracle and SQL Server.
select
id,
server_id
from
(
select
id,
server_id,
row_number() over (partition by server_id order by id) as rnk
from yourTable
) val
where rnk <= 2
Here is the demo.
| id | server_id |
| --- | --------- |
| 1 | 1 |
| 2 | 1 |
| 4 | 2 |
| 5 | 2 |
| 7 | 3 |
| 8 | 3 |

sql query to find unique records

I am new to sql and need your help to achieve the below , I have tried using group and count functions but I am getting all the rows in the unique group which are duplicated.
Below is my source data.
CDR_ID,TelephoneNo,Call_ID,call_Duration,Call_Plan
543,xxx-23,12,12,500
543,xxx-23,12,12,501
543,xxx-23,12,12,510
643,xxx-33,11,17,700
343,xxx-33,11,17,700
766,xxx-74,32,1,300
766,xxx-74,32,1,300
877,xxx-32,12,2,300
877,xxx-32,12,2,300
877,xxx-32,12,2,301
Please note :-the source has multiple combinations of unique records, so when I do the count the unique set is not appearing as count =1
example :- the below data in source have 60 records for each combination
877,xxx-32,12,2,300 -- 60 records
877,xxx-32,12,2,301 -- 60 records
I am trying to get the unique unique records, but the duplicate records are also getting in
Below are the rows which should come up in the unique group. i.e. there will be multiple call_Plans for the same combinations of CDR_ID,TelephoneNo,Call_ID,call_Duration. I want to read records for which there is only one call plan for each unique combination of CDR_ID,TelephoneNo,Call_ID,call_Duration,
CDR_ID,TelephoneNo,Call_ID,call_Duration,Call_Plan
643,xxx-33,11,17,700
343,xxx-33,11,17,700
766,xxx-74,32,1,300
Please advice on this.
Thanks and Regards
To do more complex groupings you could also use a Common Table Expression/Derived Table along with windowed functions:
declare #t table(CDR_ID int,TelephoneNo nvarchar(20),Call_ID int,call_Duration int,Call_Plan int);
insert into #t values (543,'xxx-23',12,12,500),(543,'xxx-23',12,12,501),(543,'xxx-23',12,12,510),(643,'xxx-33',11,17,700),(343,'xxx-33',11,17,700),(766,'xxx-74',32,1,300),(766,'xxx-74',32,1,300),(877,'xxx-32',12,2,300),(877,'xxx-32',12,2,300),(877,'xxx-32',12,2,301);
with cte as
(
select CDR_ID
,TelephoneNo
,Call_ID
,call_Duration
,Call_Plan
,count(*) over (partition by CDR_ID,TelephoneNo,Call_ID,call_Duration) as c
from (select distinct * from #t) a
)
select *
from cte
where c = 1;
Output:
+--------+-------------+---------+---------------+-----------+---+
| CDR_ID | TelephoneNo | Call_ID | call_Duration | Call_Plan | c |
+--------+-------------+---------+---------------+-----------+---+
| 343 | xxx-33 | 11 | 17 | 700 | 1 |
| 643 | xxx-33 | 11 | 17 | 700 | 1 |
| 766 | xxx-74 | 32 | 1 | 300 | 1 |
+--------+-------------+---------+---------------+-----------+---+
using not exists()
select distinct *
from t
where not exists (
select 1
from t as i
where i.cdr_id = t.cdr_id
and i.telephoneno = t.telephoneno
and i.call_id = t.call_id
and i.call_duration = t.call_duration
and i.call_plan <> t.call_plan
)
rextester demo: http://rextester.com/RRNNE20636
returns:
+--------+-------------+---------+---------------+-----------+-----+
| cdr_id | TelephoneNo | Call_id | call_Duration | Call_Plan | cnt |
+--------+-------------+---------+---------------+-----------+-----+
| 343 | xxx-33 | 11 | 17 | 700 | 1 |
| 643 | xxx-33 | 11 | 17 | 700 | 1 |
| 766 | xxx-74 | 32 | 1 | 300 | 1 |
+--------+-------------+---------+---------------+-----------+-----+
Basically you should try this:
SELECT A.CDR_ID, A.TelephoneNo, A.Call_ID, A.call_Duration, A.Call_Plan
FROM YOUR_TABLE A
INNER JOIN (SELECT CDR_ID,TelephoneNo,Call_ID,call_Duration
FROM YOUR_TABLE
GROUP BY CDR_ID,TelephoneNo,Call_ID,call_Duration
HAVING COUNT(*)=1
) B ON A.CDR_ID= B.CDR_ID AND A.TelephoneNo=B.TelephoneNo AND A.Call_ID=B.Call_ID AND A.call_Duration=B.call_Duration
You can do a shorter query using Windows Function COUNT(*) OVER ...
Below query will provide you the result
SELECT CDR_ID,TelephoneNo,Call_ID,call_Duration,Call_Plan, COUNT(*)
FROM TABLE_NAME GROUP BY CDR_ID,TelephoneNo,Call_ID,call_Duration,Call_Plan
HAVING COUNT(*) < 2;
It gives you with the count as well. If not required you can remove it.
Select *, count(CDR_ID)
from table
group by CDR_ID, TelephoneNo, Call_ID, call_Duration, Call_Plan
having count(CDR_ID) = 1

Selecting column from one table and count from another

t1
id | name | include
-------------------
1 | foo | true
2 | bar | true
3 | bum | false
t2
id | some | table_1_id
-------------------------
1 | 42 | 1
2 | 43 | 1
3 | 42 | 2
4 | 44 | 1
5 | 44 | 3
Desired output:
name | count(some)
------------------
foo | 3
bar | 1
What I have currently from looking through other solutions here:
SELECT a.name,
COUNT(r.some)
FROM t1 a
JOIN t2 r on a.id=r.table_1_id
WHERE a.include = 'true'
GROUP BY a.id,
r.some;
but that seems to get me
name | count(r.some)
--------------------
foo | 1
foo | 1
bar | 1
foo | 1
I'm no sql expert (I can do simple queries) so I'm googling around as well but finding most of the solutions I find give me this result. I'm probably missing something really easy.
Just remove the second column from the group by clause
SELECT a.name,
COUNT(r.some)
FROM t1 a
JOIN t2 r on a.id=r.table_1_id
WHERE a.include = 'true'
GROUP BY a.name
Columns you want to use in an aggregate function like sum() or count() must be left out of the group by clause. Only put the columns in there you want to be unique outputted.
This is because multiple column group requires the all column values to be same.
See this link for more info., Using group by on multiple columns
Actually in you case., if some are equal, table_1_id is not equal (And Vice versa). so grouping cannot occur. So all are displayed individually.
If the entries are like,
id | some | table_1_id
-------------------------
1 | 42 | 1
2 | 43 | 1
3 | 42 | 2
4 | 42 | 1
Then the output would have been.,
name | count
------------------
foo | 2 (for 42)
foo | 1 (for 43)
bar | 1 (for 42)
Actually, if you want to group on 1 column as Juergen said, you could remove r.some; from groupby clause.

How to generate an order index value (as in the order of a list) in a SELECT statement

Suppose I have these two tables :
TABLEA TABLEB
----------- -----------
ID | NAME ID | TABLEA_ID | NAME
1 | ... 1 | 1 | ...
2 | 2 | 2 | ...
3 | 3 | 2 |
4 | 4 | 2 |
5 | 3 |
6 | 3 |
7 | 4 |
8 | 2 |
I want an SQL SELECT statement that can generate such result when TABLEA.ID = TABLEB.TABLEA_ID, you can note here I don't care about grouping or ordering, I just want to generate a incremented value for each line of the same TABLEB.TABLEA_ID.
ID | TABLEA_ID | ORDER_INDEX | NAME
1 | 1 | 0 | ...
2 | 2 | 0 | ...
3 | 2 | 1 |
4 | 2 | 2 |
5 | 3 | 0 |
6 | 3 | 1 |
7 | 4 | 0 |
8 | 2 | 3 |
I tried without success to use rownum in several combination of sub-selects to generate the ORDER_INDEX depending on the value in TABLEA_ID.
Do you have hint to do that in plain SQL, is it even possible with plain SQL.
Is it possible via a PL/SQL ? And how if possible ?
Thank you very much in advance.
I believe that this is what you want:
SELECT B.ID, B.TABLEA_ID,
ROW_NUMBER() OVER(PARTITION BY B.TABLEA_ID ORDER BY B.ID) - 1 ORDER_INDEX,
B.NAME -- OR A.NAME, its not clear on your question
FROM TABLEB B
LEFT JOIN TABLEA A
ON B.TABLEA_ID = A.ID
Something like this:
SELECT
TableB.ID,
TableB.TableA_ID,
ROW_NUMBER() OVER(PARTITION BY TableB.TableA_ID ORDER BY TableB.TableA_ID) AS ORDER_INDEX,
TableB.Name
FROM
TableA
JOIN TableB
ON TableA.ID=TableB.TableA_ID
ORDER BY TableB.ID
How about
ROW_NUMBER() OVER (PARTITION BY TABLEA_ID ORDER BY ID ASC) AS ORDER_INDEX
as the definition of ORDER_INDEX