Really simple SQL query - sql

I am matching texts to keywords. I need to return all texts that contain 2 keywords (4) and (7):
TextID KeywordID
2 4
2 7
3 4
4 4
5 4
5 7
6 4
6 7
7 4
7 7
8 4
9 4
10 4
10 7
11 4
12 4
The problem is how to exclude texts that do not contain both like Text IDs 3,4,8,9,11 (they should not be in the results)?
Any help would be much appreciated!

One method uses group by and having:
select textid
from t
where keywordid in (4, 7)
group by textid
having count(*) = 2;
Use count(distinct keywordid) if the table can have duplicates.

Assuming you don't have duplicate textId-KeywordId pairs, below should work:
SELECT textid
FROM table
WHERE keywordId in (4,7)
GROUP BY textid
HAVING COUNT(*) >= 2
If you have dups, you can use count(distinct keywordId) as per #Gordon's answer.
Update
Here's MS Access query:
SELECT tblPerformanceKeyword.TextID
FROM tblPerformanceKeyword
WHERE tblPerformanceKeyword.KeywordID = 4 Or tblPerformanceKeyword.KeywordID = 7
GROUP BY tblPerformanceKeyword.TextID
HAVING COUNT(tblPerformanceKeyword.KeywordID) >= 2;

Related

Row Number with specific window size

I want to group records by row numbers.
Like from row 1-3 in group 1 , 4-6 in group 2 , 7-9 in group 3 and so on.
Suppose below is the table structure:
Row NumberDataValue
1 A 10
2 A 5
3 A 1
4 A 33
5 A 2
6 A 127
1 B 1
2 B 0
3 B 7
4 B 7
5 B 5
6 B 8
7 B 1
8 B 0
I want a output like this:
GroupValue
1 10
1 5
1 1
2 33
2 2
2 127
1 1
1 0
1 7
2 7
2 5
2 8
3 1
3 0
I am using Oracle 11G.
I can achieve this using PL/SQL. But I have to use SQL only. As I have to use this query in a reporting tool.
If this is a duplicate question please provide the link of the answered question.
Subtract 1 from the column "RowNumber" and divide by 3.
Then use TRUNC() to get the integer part:
SELECT TRUNC(("RowNumber" - 1) / 3) + 1 "Group",
"Value"
FROM tablename
See the demo.
I would assume the name of the first column is ordering.
You can do:
select
1 + trunc(row_number() over(partition by data order by ordering) - 1) / 3,
value
from t
What you show looks like the output from something like this:
select ceil(rn/3) as grp, value
from your_table
order by rn;
Note that "row number" and "group" are reserved words/phrases which should not be used as column names. I used rn and grp instead.
I think the ceiling function is the simplest way to arrive at what you want. If you want to base it on the RowNumber column:
select ceil( RowNumber / 3.0) as grouping
If you want to calculate it yourself using row_number():
select ceil( row_number() over (order by RowNumber) / 3.0 ) as grouping

Make a query to display unmatched data

I m having difficulty making a query that displays unmatched data in between 2 tables.
The tables are:
Employee data Salary data
ID Holidays ID Holiday
1 10 0 10
2 8 1 5
3 5 2 8
4 7 3 5
5 8 7 6
6 5 8 9
7 6 9 2
8 9 10 3
the primary key is ID for both tables.
I want my query result to contain all the values that does not match in both tables.
The type of output i want is something like this:
ID Holiday
0 10
1 10
1 5
4 7
5 8
6 5
9 2
10 3
I tried using unmatched query wizard but that only compares ID, not the Holiday column.
Please help me!
You could use a union of two exists queries:
SELECT ID, Holiday FROM Employee as e
WHERE NOT EXISTS (SELECT 1 FROM Salary as s WHERE s.ID = e.ID AND s.Holiday = e.Holiday)
UNION ALL
SELECT ID, Holiday FROM Salary as s
WHERE NOT EXISTS (SELECT 1 FROM Employee as e WHERE e.ID = s.ID AND e.Holiday = s.Holiday);

Output all duplicate rows (SQL Server)

I have a table which holds what I consider duplicate rows. the values in these records may not be exactly the same, but it’s been calculated that they’re possible duplicates by fuzzy logic. For example:
RecordCD key_in key_out
---------------------------
1 1 2
2 2 2
3 3 3
4 4 6
5 5 5
6 6 6
7 7 7
8 8 11
9 9 9
10 10 10
11 11 11
key_in column has a unique ID of the record.
key_out column has a possible duplicate if it’s not equal to key_in
I need my output to look like this and list all of the possible duplicates:
RecordCD key_in key_out
---------------------------
1 1 2
2 2 2
4 4 6
6 6 6
8 8 11
11 11 11
but I’m struggling to construct a query that would do that.
Thanks.
I think this is what you want:
select t.*
from t
where exists (select 1
from t t2
where t2.key_out = t.key_out and t2.key_in <> t.key_in
)
order by t.key_out;
Here is a db<>fiddle.
It seems like if there is a mismatch between key_in, key_out you want to pull all rows where key_in has either value`
I would create a temp table with all values in rows with mismatched key_in, key_out, call this value bad_match
If either of your key_in, key_out values match this value, include it in output
select mytable.* from mytable
where key_in in
(select key_in bad_match from mytable where key_in <> key_out
union all
select key_out from mytable where key_in <> key_out);
This sample builds your schema and returns the desired output

How to combine sum by same id in sql

I have table like this:
ID COUNT
-----------
7 2
7 2
8 3
8 3
9 4
9 4
And I want to summarise COUNT with same ID to have
ID COUNT
-----------
7 4
8 6
9 8
How to get it in oracle db?
EDIT:
I get my table from pipelined function with this type:
TYPE g_item IS RECORD (
g_id NUMBER,
g_count VARCHAR2(50),
g_who VARCHAR2(50)
);
Code to get correct table:
SQL> select g_id, sum(g_count)
from (SELECT * from TABLE(my_package.get_items_tab ()))
group by g_id;
G_ID SUM(G_COUNT)
----- ------------
1 9
6 7
2 7
4 7
5 7
3 7
7 7
7 rows selected.
EDIT2:
Oh.. it's my fault, I must group it by g_who, not by g_id
select id, sum(count)
from your_table
group by id
This is a simple group by operation:
select id,
sum(count) as total_count
from the_table
group by id
order by id;
Btw: it's a bad habit to use reserved words (count) as column names.

How to get a regular rank without OLAP functions

I want to do regular rank rows without OLAP functions(no RANK() or sth like that). I want to create a "Top-10" list of the users with the shortes average response time. I got this query below:
WITH table_avg (NICKNAME, AVG_RESPONSETIME) AS
(SELECT r.nickname,
AVG ((timestampdiff(32,char(timestamp(e1.date) -timestamp(e2.date)))))AS AVG_RESPONSETIME
FROM email e1,
email e2,
address a,
use u,
user r
WHERE e2.id=e1.in_reply_to
AND e1.from=a.id
AND a.id=u.address
AND u.user=r.id
GROUP BY r.nickname HAVING count(r.nickname)>=3
ORDER BY 1 ASC,2 ASC)
SELECT a.NICKNAME,
a.AVG_RESPONSETIME,
count(DISTINCT b.AVG_RESPONSETIME) AS RANK
FROM table_avg a,
table_avg b
WHERE b.AVG_RESPONSETIME<=a.AVG_RESPONSETIME
GROUP BY a.NICKNAME,
a.AVG_RESPONSETIME HAVING count(DISTINCT b.AVG_RESPONSETIME) <=10
ORDER BY RANK ASC,
a.NICKNAME ASC
The result is:
NICKNAME AVG_RESPONSETIME RANK
----------- ---------------- ----
cyber426 1 1
neo927 1 1
neo259 3 2
cypher15 4 3
fool28 5 4
cyber974 6 5
hacker285 6 5
dau719 7 6
trinity407 7 6
fool380 8 7
wiesel509 8 7
dau814 10 8
morpheus462 10 8
neo517 10 8
drago831 11 9
drago861 13 10
How can I get the rank to skip the number 2? It should be number 3, the result that I'd like is:
NICKNAME AVG_RESPONSETIME RANK
---------- ------------------- -----
cyber426 1 1
neo927 1 1
neo259 3 3
cypher15 4 4
fool28 5 5
cyber974 6 6
hacker285 6 6
dau719 7 8
trinity407 7 8
fool380 8 10
wiesel509 8 10
I cannot use RANK function, this is a exercise that I should do.
Thanks in advance!!!
I found a complicated way to do what you wanted to do with a standard select statement. You still have to find out why it works (I know why). I don't give you the explanation, so that you need to think about it and have a chance to learn. An easier option would be to use cursors.
SELECT a.NICKNAME,
a.AVG_RESPONSETIME,
count(b.AVG_RESPONSETIME) + 1 - count(case (a.AVG_RESPONSETIME - b.AVG_RESPONSETIME) when 0 then 1 else NULL end) as rank
FROM table_avg a, table_avg b
WHERE b.AVG_RESPONSETIME<=a.AVG_RESPONSETIME
GROUP BY a.NICKNAME, a.AVG_RESPONSETIME HAVING count(b.AVG_RESPONSETIME) <=10
ORDER BY RANK ASC, a.NICKNAME ASC;
tested with ideone.com - http://ideone.com/9F4gFo