Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
External subject group
| pk | group_id | subid |
|----|----------|-------|
| 1 | 1 | s1 |
| 2 | 1 | s2 |
| 3 | 1 | s3 |
| 4 | 2 | x1 |
| 5 | 2 | x2 |
| 6 | 3 | y1 |
| 7 | 3 | y2 |
| 8 | 3 | y3 |
Internal subject group
| pk | group_id | subid |
|----|----------|-------|
| 1 | 1 | a1 |
| 2 | 1 | a2 |
| 3 | 1 | a3 |
| 4 | 2 | b1 |
| 5 | 3 | c1 |
| 5 | 3 | c2 |
| 7 | 3 | c3 |
| 8 | 3 | b4 |
I am using php and sql (oracle) at the moment. For example,
I have array of external subjects:
[s1, s2, s3]
I have array of internal subjects
[a1, a2, a3]
My attempt is that (incorrectly)
SELECT
group_id
FROM
external_subject_group e_s_g,
internal_subject_group i_s_g
WHERE
e_s_g.group_id = i_s_g.group_id AND
e_s_g.subid = "s1" AND
e_s_g.subid = "s2" AND
e_s_g.subid = "s3" AND
i_s_g.subid = "a1" AND
i_s_g.subid = "b1" AND
i_s_g.subid = "c1"
The group id either exist or empty.
Basically, I try to wrap this sql query into a php function. If the query returns the relationship id. I know the relationship [s1, s2, s3] x [a1, a2, a3] exist.
for example, another relationship is [x1, x2] x [b1].
I suspect you want more than just a simple where condition, and that you are looking for a way to identify a group that has all 3 values. Here are a couple of alternative queries. The first is my best guess, the second is just for comparison and you can trial these examples at SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Table1
(PK int, GROUP_ID int, SUBID varchar2(20))
;
INSERT ALL
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (1, 1, 's1')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (2, 1, 's2')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (3, 1, 's3')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (4, 2, 'x1')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (5, 2, 'x2')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (6, 3, 'y1')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (7, 3, 'y2')
INTO Table1 (PK, GROUP_ID, SUBID)
VALUES (8, 3, 'y3')
SELECT * FROM dual
;
The following query uses GROUP BY and HAVING SUM(...) as a constct to require that ALL 3 wanted subid's MUST be used.
Query 1:
select group_id
from Table1
group by group_id
having SUM(case when subid in('s1','s2','s3') then 1 else 0 end) = 3
Result:
| GROUP_ID |
|----------|
| 1 |
Query 2:
This query only requires that ANY ONE of the subids listed have been used.
select distinct group_id
from Table1
where subid in('s1','s2','s3')
Result:
| GROUP_ID |
|----------|
| 1 |
+EDIT
You might also need to use UNION ALL
select group_id
from (
select pk,group_id,subid from external_subject_group e_s_g
UNION ALL
select pk,group_id,subid from internal_subject_group i_s_g
) t1
group by group_id
having SUM(case when subid in('s1','s2','s3','a1','a2','a3') then 1 else 0 end) = 6
Related
Given an example of table:
id | item_id | user_id | bid_price
----------------------------------
The task is to select rows with minimum bid_price for each item_id in the provided set.
For example: item_id = [1, 2, 3] - so I need to select up to three (3) rows, having a minimum bid_price.
Example of data:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
2 | 1 | 12 | 2
3 | 1 | 13 | 3
4 | 1 | 14 | 1
5 | 1 | 15 | 4
6 | 2 | 16 | 2
7 | 2 | 17 | 1
8 | 3 | 18 | 2
9 | 3 | 19 | 3
10 | 3 | 18 | 2
Expected result:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
7 | 2 | 17 | 1
8 | 3 | 18 | 2
Actually, I'm using Symfony/Docine DQL, but it will be enough with a plain SQL example.
For the all the columns in the rows you could use a inner join on subselect for min bid price
select m.id, m.item_id, m.user_id, m.bid_price
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
or .. if you have some float data type you could use a acst for unsigned
select m.id, m.item_id, m.user_id, cast(m.bid_price as UNSIGNED)
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
You can use MIN() with GROUP BY in the query:
SELECT id, item_id, MIN(bid_price) AS min_bid, user_id
FROM your_tbl
GROUP BY item_id
HAVING item_id in(1, 2, 3);
Use this query:
SELECT id, item_id, user_id, min(bid_price) as bid_price
FROM YOUR_TABLE_NAME
GROUP BY item_id;
I want to realize a search similar to mysql search title, description and multi rows tag.
Here are my tables:
Books:
+----+-----------------------+-------------+
| id | name | description |
+----+-----------------------+-------------+
| 1 | Me Before You | [TEXT] |
| 2 | How To Win Friends... | [TEXT] |
| 3 | The Girl on the Train | [TEXT] |
| 4 | After You | [TEXT] |
| 5 | We Were Liars | [TEXT] |
+----+-----------------------+-------------+
Tags:
+----+-----------------------+
| id | tag |
+----+-----------------------+
| 1 | romance |
| 2 | thriller |
| 3 | fantasy |
| 4 | science fiction |
| 5 | drama |
| 6 | friends |
+----+-----------------------+
Books_tags:
+---------+--------+
| book_id | tag_id |
+---------+--------+
| 1 | 1 |
| 1 | 3 |
| 2 | 3 |
| 3 | 3 |
| 3 | 5 |
| 4 | 1 |
| 4 | 5 |
| 4 | 6 |
| 5 | 2 |
| 5 | 6 |
+---------+--------+
Here are some example searches and the desired results:
'romance' -> books 1, 4
'friends' -> books 2, 4, 5
'friends win' -> books 2
'fantasy' -> books 2, 3
'fantasy train' -> books 3
Before building the SQL query, a function checks every given keyword if it's even a tag at once. My problem is, for example, in this case:
Case: 3 /
Keywords: friends win /
Tags: friends
Query:
SELECT SQL_CALC_FOUND_ROWS
b.id, b.name,
MATCH(b.name) AGAINST('*friends* *win*' IN BOOLEAN MODE) as name_score,
MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)as tag_score
FROM
books b
LEFT JOIN
books_tags bt ON bt.book_id = b.id
LEFT JOIN
tags t ON t.id = bt.tag_id
WHERE
MATCH(b.name) AGAINST('*friends win*' IN BOOLEAN MODE)
OR MATCH(t.tag) AGAINST('friends' IN BOOLEAN MODE)
GROUP BY
b.id
ORDER BY
name_score DESC, (tag_score + name_score) DESC
Results:
array (size=3)
0 => string '2' (length=1)
1 => string '4' (length=1)
2 => string '5' (length=1)
In this case, the keyword 'friends' already matches the title, so the condition must be reduced and should not search the tags anymore. How can I solve it?
Is this what you're after?...
Data set
DROP TABLE IF EXISTS books;
CREATE TABLE books
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,name VARCHAR(50) NOT NULL
,FULLTEXT(name)
) ENGINE = MyISAM;
INSERT INTO books VALUES
(1,'Me Before You'),
(2,'How To Win Friends...'),
(3,'The Girl on the Train'),
(4,'After You'),
(5,'We Were Liars');
DROP TABLE IF EXISTS tags;
CREATE TABLE tags
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,tag VARCHAR(20) NOT NULL
);
INSERT INTO tags VALUES
(1,'romance'),
(2,'thriller'),
(3,'fantasy'),
(4,'science fiction'),
(5,'drama'),
(6,'friends');
DROP TABLE IF EXISTS books_tags;
CREATE TABLE books_tags
(book_id INT NOT NULL
,tag_id INT NOT NULL
,PRIMARY KEY(book_id,tag_id)
);
INSERT INTO books_tags VALUES
(1,1),
(1,3),
(2,3),
(3,3),
(3,5),
(4,1),
(4,5),
(4,6),
(5,2),
(5,6);
Query and result
SELECT DISTINCT b.*
, MATCH(b.name) AGAINST('*friends* *win*' IN BOOLEAN MODE) name_score
FROM books b
LEFT
JOIN books_tags bt
ON bt.book_id = b.id
LEFT
JOIN tags t
ON t.id = bt.tag_id
AND t.tag IN ('friends','win')
WHERE t.id IS NULL;
+----+-----------------------+------------+
| id | name | name_score |
+----+-----------------------+------------+
| 1 | Me Before You | 0 |
| 2 | How To Win Friends... | 1 |
| 3 | The Girl on the Train | 0 |
| 4 | After You | 0 |
| 5 | We Were Liars | 0 |
+----+-----------------------+------------+
Ok, finally I wrote a function, that generates a working query for me. The function is very complex and depends on several user inputs. The solution is to concatenate t.tag and b.name. This is, how my WHERE-condition looks like and it work's fine for me:
... WHERE ap.active='yes'
AND (LOWER(CONCAT_WS(' ', IF(LENGTH(t.tag), t.tag, NULL), IF(LENGTH(b.name), b.name, NULL) )) REGEXP 'friends'
AND LOWER(CONCAT_WS(' ', IF(LENGTH(t.tag), t.tag, NULL), IF(LENGTH(b.name), b.name, NULL) )) REGEXP 'win')
GROUP BY b.id
I have a table like this:
// mytable
+----+---------+---------+
| id | related | color |
+----+---------+---------+
| 1 | 1 | red |
| 2 | 1 | blue |
| 3 | 3 | green |
| 4 | 1 | white |
| 5 | 3 | brown |
| 6 | 6 | gray |
| 7 | 3 | black |
| 8 | 1 | orange |
| 9 | 6 | pink |
+----+---------+---------+
I have an id number and I need to get the color of related id.
For example:
$id = 4; // I need to get `red`
$id = 5; // I need to get `green`
$id = 6; // I need to get `gray`
$id = 9; // I need to get `gray`
I can do that by using a JOIN. Something like this:
SELECT t2.color FROM mytable t1 JOIN mytable t2 ON t1.related = t2.id WHERE t1.id = :id
My query works as expected .. But I'm not sure using a JOIN for doing that is standard. Actually I'm trying to know is there any better approach? Or mine is a normal way?
What's wrong with SELECT t.related FROM mytable t WHERE t.id = :id? JOIN makes nothing more but checking if there is a actual id in 'related' column or not
I've done two different query and explain them, hope can give you some hints.
SQL Fiddle
MySQL 5.6 Schema:
CREATE TABLE mytable
(`id` int, `related` int, `color` varchar(6))
;
INSERT INTO mytable
(`id`, `related`, `color`)
VALUES
(1, 1, 'red'),
(2, 1, 'blue'),
(3, 3, 'green'),
(4, 1, 'white'),
(5, 3, 'brown'),
(6, 6, 'gray'),
(7, 3, 'black'),
(8, 1, 'orange'),
(9, 6, 'pink')
;
Query 1:
SELECT t2.color FROM mytable t1 JOIN mytable t2 ON t1.related = t2.id WHERE t1.id = '4'
Results:
| color |
|-------|
| red |
Query 2:
explain SELECT t2.color FROM mytable t1 JOIN mytable t2 ON t1.related = t2.id WHERE t1.id = '4'
Results:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|-------------|-------|------|---------------|--------|---------|--------|------|----------------------------------------------------|
| 1 | SIMPLE | t1 | ALL | (null) | (null) | (null) | (null) | 9 | Using where |
| 1 | SIMPLE | t2 | ALL | (null) | (null) | (null) | (null) | 9 | Using where; Using join buffer (Block Nested Loop) |
Query 3:
SELECT t1.color FROM mytable t1 WHERE exists (select 1 from mytable t2 where t1.id = t2.related and t2.id ='4')
Results:
| color |
|-------|
| red |
Query 4:
explain SELECT t1.color FROM mytable t1 WHERE exists (select 1 from mytable t2 where t1.id = t2.related and t2.id ='4')
Results:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|--------------------|-------|------|---------------|--------|---------|--------|------|-------------|
| 1 | PRIMARY | t1 | ALL | (null) | (null) | (null) | (null) | 9 | Using where |
| 2 | DEPENDENT SUBQUERY | t2 | ALL | (null) | (null) | (null) | (null) | 9 | Using where |
you can handle this in simple ways also
select t.color from mytable t where t.id = '$id' (for one value)
select t.color from mytable t where t.id in ('$id1','$id2','$id3','$id4' ) (for multi-values comma separated strings)
I have two tables like so:
# Match
id, team1_id , team2_id
-----------------------
1, 10, 20
2, 10, 50
# Team
id, team_name, team_country
---------------------------
10, team A , England
20, team B , France
I'm trying to get the list from Match table with both teams info,
I wanna some thing like :
Team A (England) vs Team B (France)
I tried this one, but I got false team info, some thing wrong with my query for sure.
Here's my query :
SELECT `match`.*,
`t1`.`team_country` as team1_country,
`t2`.`team_country` as team2_country
FROM `match`,
`team` t1 , `team` t2
WHERE `match`.`team1_id` = `t1`.`id` and `match`.`team2_id` = `t2`.`id`
Thanks in advance!
I just fiddled it on my testmachine with postgres. The SQL shouldn't be different:
lara=# create table match ( id serial primary key, team1 int, team2 int);
CREATE TABLE
lara=# create table teams ( id serial primary key, name text, country text);
CREATE TABLE
lara=# insert into match(id, team1, team2) values (1,1,2),(2,1,3),(3,2,1);
INSERT 0 3
lara=# select * from match;
id | team1 | team2
----+-------+-------
1 | 1 | 2
2 | 1 | 3
3 | 2 | 1
(3 rows)
lara=# insert into teams values (1, 't1', 'en');
INSERT 0 1
lara=# insert into teams values (2, 't2', 'de');
INSERT 0 1
lara=# insert into teams values (3, 't3', 'fr');
INSERT 0 1
lara=# select * from match m left join teams t1 on t1.id=m.team1 left join teams t2 on t2.id=m.team2;
id | team1 | team2 | id | name | country | id | name | country
----+-------+-------+----+------+---------+----+------+---------
1 | 1 | 2 | 1 | t1 | en | 2 | t2 | de
2 | 1 | 3 | 1 | t1 | en | 3 | t3 | fr
3 | 2 | 1 | 2 | t2 | de | 1 | t1 | en
So your actual query is correct. A cleaner one would be the following:
SELECT * FROM match m
LEFT JOIN teams t1 ON t1.id=m.team1
LEFT JOIN teams t2 ON t2.id=m.team2;
But your problem is obviously not the SQL.
i have 2 table one is buy_table and another is sale_table. in this query in this query i will have to use SUM , group by and date also but i am not able to understand and its showing som error
//buy table
----------------------------------------------------------
| id | product_id | quantity | total_price | date |
----------------------------------------------------------
| 1 | 1 | 5 | 500 | 2014-12-05 |
----------------------------------------------------------
| 2 | 2 | 5 | 500 | 2014-12-15 |
----------------------------------------------------------
| 3 | 1 | 5 | 500 | 2014-12-01 |
//Sale_table
----------------------------------------------------------
| id | product_id | quantity | total_price | date |
----------------------------------------------------------
| 1 | 1 | 5 | 1800 | 2014-12-05 |
----------------------------------------------------------
| 2 | 2 | 5 | 500 | 2014-12-15 |
----------------------------------------------------------
| 3 | 3 | 5 | 500 | 2015-01-01 |
----------------------------------------------------------
| 4 | 3 | 5 | 500 | 2015-01-01 |
i need like this.
----------------------------------------------------------------------
| id | product_id |buy_quantity| buy_total | sale_quantity|sale_total
----------------------------------------------------------------------
| 1 | 1 | 10 | 1000 | 5 | 1800
----------------------------------------------------------------------
| 2 | 2 | 5 | 500 | 5 | 500
----------------------------------------------------------------------
| 3 | 3 | 5 | 500 | 10 | 1000
----------------------------------------------------------------------
SELECT
A.ID,A.PRODUCT_ID,A.BUY_QUANTITY,B.SALE_QUANTITY,A.BUY_TOTAL,B.SALE_TOTAL,A.DATE
(select id,product_id,sum(quantity) as buy_quantity,sum(total_price) as
buy_total,date from buy_table group by product_id) A INNER JOIN (SELECT sum
(quantity) as SALE_quantity,sum(total_price) as SALE_total FROM SALE_TABLE group by product_id) B
ON A.PRODUCT_ID=B.PRODUCT_ID
I will suppose that you mistyped the third row in buy table and you meant to type 3 in product_id and the id column in the desired result set is just a serial which is not relevant to any data. The below query might be the answer for your inquiry:
-- Simluating your tables
DECLARE #buyTable AS TABLE (id INT, product_id INT, quantity INT, total_price INT, date DATE)
DECLARE #saleTable AS TABLE (id INT, product_id INT, quantity INT, total_price INT, date DATE)
INSERT INTO #buyTable
VALUES(1, 1, 5, 500, '2014-12-05'), (2, 2, 5, 500, '2014-12-15'), (3, 3, 5, 500, '2014-12-01')
INSERT INTO #saleTable
VALUES(1, 1, 5, 1800, '2014-12-05'), (2, 2, 5, 500, '2014-12-15'), (3, 3, 5, 500, '2014-01-01'), (4, 3, 5, 500, '2015-01-01')
-- Simluation stops here
SELECT ROW_NUMBER() OVER(ORDER BY b.product_id) AS id, b.product_id, buy_quantity, buy_total, sale_quantity, sale_total FROM
(
SELECT product_id, SUM(quantity) AS buy_quantity, SUM(total_price) AS buy_total FROM #buyTable
GROUP BY product_id
) b
INNER JOIN
(
SELECT product_id, SUM(quantity) AS sale_quantity, SUM(total_price) AS sale_total FROM #saleTable
GROUP BY product_id
) s ON s.product_id = b.product_id
The id column in your results doesn't make sense if you want to show buy/sale by product.
To ensure you always get all the products, you need to use your product table as the driving table (Assuming you have a product table)
select
p.product_id,
(SELECT SUM(b.quantity) FROM buy b WHERE b.product_id = p.product_id) as buy_quantity,
(SELECT SUM(b.total_price) FROM buy b WHERE b.product_id = p.product_id) as buy_total,
(SELECT SUM(s.quantity) FROM sale s WHERE s.product_id = p.product_id) as sale_quantity,
(SELECT SUM(s.total_price) FROM sale s WHERE s.product_id = p.product_id) as sale_total
from product p