select multi row inside of a table (not same condition) - sql

I try to explain an issue I have faced nowadays.
Actually I have designed a table in order to track the changes applying by users inside of a depot of NLP engine.
I have two table named Token And Lexeme. each token has an id that directly connect to a row of lexeme table. and always I can find the latest and updated lexemes by looking up to token table.
here is their scheme:
Token Table:
+-----+----------+----------+
| Id | token |LexemeId* |
+-----+----------+----------+
LexemeId refers to a row inside of lexeme table.
Lexeme Table:
+-----+---------------------+-------------+
| Id | some information |UpdatedFrom* |
+-----+---------------------+-------------+
* UpdatedFrom field refers another row inside of Lexeme Table.
Null means there is no more rows related to this token(lexeme).
an example:
Token Table:
+-----+----------+----------+
| 0 | A |4 |
| 1 | B |1 |
+-----+----------+----------+
Lexeme Table:
+-----+----------------------+-------------+
| 0 | A information#1 |NULL |
| 1 | B information |NULL |
| 2 | A information#2 |0 |
| 3 | A information#3 |2 |
| 4 | A information#4 |3 |
+-----+----------------------+-------------+
I hope I could clear the air.
I want to write a store procedure to collect all records related to each token. for example for token 'A', I'm expected to have an array (or data table) looks like this:
+-----+----------------------+-------------+
| id | informations | updated from|
+-----+----------------------+-------------+
| 0 | A information#1 |NULL |
| 2 | A information#2 |0 |
| 3 | A information#3 |2 |
| 4 | A information#4 |3 |
+-----+----------------------+-------------+
anybody has any idea to help me....
my knowledge on sql transcript is summarized to Update, Insert and select statements, not more!
thanks in advanced...

Assuming this is in an RDBMS that supports recursive CTEs, try:
with cte as
(select t.id TokenId, t.token, l.Id, l.SomeInformation, l.UpdatedFrom
from Token t
join Lexeme l on t.LexemeId = l.id
union all
select t.TokenId, t.token, l.Id, l.SomeInformation, l.UpdatedFrom
from cte t
join Lexeme l on t.UpdatedFrom = l.id)
select Id, SomeInformation, UpdatedFrom
from cte
where TokenId=0 /* token = 'A' */
SQLFiddle here.

Related

Trying to use SQL to group accounts by number of sub-types

I'm using a table that houses account info. These accounts can have between 1 and 6 unique sub types. Currently it only tracks between single and multi subtypes but doesn't show the totals of how many of each multi sub-type account there are (how many accounts with 2 subtypes vs. 3 subtypes and so on). I'm looking for a wholly SQL way to view how many of each grouping of account types. There are a LOT of accounts in the table so pulling it manually isn't really an option. Is there a way I can get a count of each of the amount of sub-type groupings?
| account | Sub-Type | Single_V_Multi |
|---------|--------- | -------------- |
|123456789|123456789 | Multi |
|123456789|123456790 | Multi |
|123456789|123456791 | Multi |
|123456792|123456792 | Single |
|123456793|123456793 | Multi |
|123456793|123456794 | Multi |
|123456795|123456795 | Single |
|123456796|123456796 | Single |
|123456797|123456797 | Single |
|123456798|123456798 | Single |
|123456799|123456799 | Multi |
|123456799|123456800 | Multi |
|123456799|123456801 | Multi |
|123456799|123456802 | Multi |
From this example I'd be looking to get separate counts of the Account column based on the number of unique Sub-Type. What I've done so far is a query that groups the Sub-Types:
SELECT account, COUNT(DISTINCT(Sub-Type)) as BAN_SUB_COUNT
FROM Table
Which give the output:
| account | BAN_SUB_COUNT |
| ------- | ------------- |
|123456789| 3 |
|123456792| 1 |
|123456793| 2 |
|123456795| 1 |
|123456796| 1 |
|123456797| 1 |
|123456798| 1 |
|123456799| 4 |
What I need from this is a way to get a separate count of accounts for each of the distinct BAN_SUB_COUNT entries. Ideally it would be along the lines of:
| BAN_SUB_COUNT |count of Accounts|
| ------------- | --------------- |
| 1 | 5 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
Sorry for any confusion and I hope I'm explaining myself better here!
You just need to wrap your query with another one:
select ban_sub_count, count(distinct account) as count_of_accounts
from (
SELECT account, COUNT(DISTINCT Sub-Type ) as BAN_SUB_COUNT
FROM Table
group by account
)z
group by ban_sub_count
Output:
BAN_SUB_COUNT
count of Accounts
1
5
2
1
3
1
4
1
I try to answer your question:
select a2.*,a.`count_sub_type`
FROM (
select count(`sub-type`) as count_sub_type,`sub-type` from account group by `sub-type`
) a
left join account a2 on a2.`sub-type` = a.`sub-type`;
output :
|account |sub-type|single_v_multi|count_sub_type|
|--------|--------|--------------|--------------|
|account6|type1 |multiview |3 |
|account5|type1 |single |3 |
|account1|type1 |single |3 |
|account4|type2 |single |2 |
|account2|type2 |single |2 |
|account6|type3 |single |2 |
|account3|type3 |single |2 |
Best regards,

Count string occurrences within a list column SQL/Grafana

I have a table in the following format:
| id | tags |
|----|-------------------------|
|1 |['Car', 'Plane', 'Truck']|
|2 |['Plane', 'Truck'] |
|3 |['Car', 'Plane'] |
|4 |['Plane'] |
|5 |['Boat', 'Truck'] |
How can I create a table that gives me the total number of occurrences of each item in all cells of the "tags" column? Items ideally do not include single quotes, but may if necessary.
The resulting table would look like:
| tag | count |
|-------|-------|
| Car | 2 |
| Plane | 4 |
| Truck | 3 |
| Boat | 1 |
The following does not work because it only counts identical "tags" entries rather than comparing list contents.
SELECT u.id, count(u.tags) as cnt
FROM table u
group by 1
order by cnt desc;
I am aware of this near-identical question, but they are using Snowflake/SQL whereas I am using MySQL/Grafana so the accepted answer uses functions unavailable to me.

SQL - Given sequence of data, how do I query the origin?

Let's assume we have the following data.
| UUID | SEENTIME | LAST_SEENTIME |
------------------------------------------------------
| UUID1 | 2020-11-10T05:00:00 | |
| UUID2 | 2020-11-10T05:01:00 | 2020-11-10T05:00:00 |
| UUID3 | 2020-11-10T05:03:00 | 2020-11-10T05:01:00 |
| UUID4 | 2020-11-10T05:04:00 | 2020-11-10T05:03:00 |
| UUID5 | 2020-11-10T05:07:00 | 2020-11-10T05:04:00 |
| UUID6 | 2020-11-10T05:08:00 | 2020-11-10T05:07:00 |
Each data is connected to each other via LAST_SEENTIME.
In such case, is there a way to use SQL to identify these connected events as one? I want to be able to calculate start and end to calculate the duration of this event.
You can use a recursive CTE. The exact syntax varies by database, but something like this:
with recursive cte as
select uuid as orig_uuid, uuid, seentime
from t
where last_seentime is null
union all
select cte.orig_uuid, t.uuid, t.seentime
from cte join
t
on cte.seentime = t.last_seentime
)
select orig_uuid,
max(seentime) - min(seentime) -- or whatever your database uses
from cte
group by orig_uuid;

SELECTing Related Rows Based on a Single Row Match

I have the following table running on Postgres SQL 9.5:
+---+------------+-------------+
|ID | trans_id | message |
+---+------------+-------------+
| 1 | 1234567 | abc123-ef |
| 2 | 1234567 | def234-gh |
| 3 | 1234567 | ghi567-ij |
| 4 | 8902345 | ced123-ef |
| 5 | 8902345 | def234-bz |
| 6 | 8902345 | ghi567-ij |
| 7 | 6789012 | abc123-ab |
| 8 | 6789012 | def234-cd |
| 9 | 6789012 | ghi567-ef |
|10 | 4567890 | abc123-ab |
|11 | 4567890 | gex890-aj |
|12 | 4567890 | ghi567-ef |
+---+------------+-------------+
I am looking for the rows for each trans_id based on a LIKE query, like this:
SELECT * FROM table
WHERE message LIKE '%def-234%'
This, of course, returns just three rows, the three that match my pattern in the message column. What I am looking for, instead, is all the rows matching that trans_id in groups of messages that match. That is, if a single row matches the pattern, get all the rows with the trans_id of that matching row.
That is, the results would be:
+---+------------+-------------+
|ID | trans_id | message |
+---+------------+-------------+
| 1 | 1234567 | abc123-ef |
| 2 | 1234567 | def234-gh |
| 3 | 1234567 | ghi567-ij |
| 4 | 8902345 | ced123-ef |
| 5 | 8902345 | def234-bz |
| 6 | 8902345 | ghi567-ij |
| 7 | 6789012 | abc123-ab |
| 8 | 6789012 | def234-cd |
| 9 | 6789012 | ghi567-ef |
+---+------------+-------------+
Notice rows 10, 11, and 12 were not SELECTed because there was not one of them that matched the %def-234% pattern.
I have tried (and failed) to write a sub-query to get the all the related rows when a single message matches a pattern:
SELECT sub.*
FROM (
SELECT DISTINCT trans_id FROM table WHERE message LIKE '%def-234%'
) sub
WHERE table.trans_id = sub.trans_id
I could easily do this with two queries, but the first query to get a list of matching trans_ids to include in a WHERE trans_id IN (<huge list of trans_ids>) clause would be very large, and would not be a very inefficient way of doing this, and I believe there exists a way to do it with a single query.
Thank you!
This will do the job I think :
WITH sub AS (
SELECT trans_id
FROM table
WHERE message LIKE '%def-234%'
)
SELECT *
FROM table JOIN sub USING (trans_id);
Hope this help.
Try this:
SELECT ID, trans_id, message
FROM (
SELECT ID, trans_id, message,
COUNT(*) FILTER (WHERE message LIKE '%def234%')
OVER (PARTITION BY trans_id) AS pattern_cnt
FROM mytable) AS t
WHERE pattern_cnt >= 1
Using a FILTER clause in the windowed version of COUNT function we can get the number of records matching the predefined pattern within each trans_id slice. The outer query uses this count to filter out irrelevant slices.
Demo here
You can do this.
WITH trans
AS
(SELECT DISTINCT trans_id
FROM t1
WHERE message LIKE '%def234%')
SELECT t1.*
FROM t1,
trans
WHERE t1.trans_id = trans.trans_id;
I think this will perform better. If you have enough data, you can do an explain on both Sub query and CTE and compare the output.

SQL Insert Query For Multiple Max IDs

Table w:
|ID|Comment|SeqID|
|1 |bajg | 1 |
|1 |2423 | 2 |
|2 |ref | 1 |
|2 |comment| 2 |
|2 |juk | 3 |
|3 |efef | 1 |
|4 | hy | 1 |
|4 | 6u | 2 |
How do I insert a standard new comment for each ID for a new SeqID (SeqID increase by 1)
The Below query results in the highest SeqID:
Select *
From w
Where SEQID =
(select max(seqid)
from w)
Table w:
|2 |juk | 3 |
Expected Result
Table w:
|ID|Comment|SeqID|
|1 |sqc | 3 |
|2 |sqc | 4 |
|3 |sqc | 2 |
|4 |sqc | 3 |
Will I have to go through and insert all the values (new comment as sqc) I want into the table using the below, or is there a faster way?
INSERT INTO table_name
VALUES (value1,value2,value3,...);
Try this:
INSERT INTO mytable (ID, Comment, SeqID)
SELECT ID, 'sqc', MAX(SeqID) + 1
FROM mytable
GROUP BY ID
Demo here
You are probably better off just calculating the value when you query. Define an identity column on the table, say CommentId and run a query like:
select id, comment,
row_number() over (partition by comment order by CommentId) as SeqId
from t;
What is nice about this approach is that the ids are always sequential, you don't have no opportunities for duplicates, the table does not have to be locked to when inserting, and the sequential ids work even for updates and deletes.