The following are the list of different kinds of books that customers read in a library. The values are stored with the power of 2 in a column called bookType.
I need to fetch list of books with the combinations of persons who read
only Novel Or only Fairytale Or only BedTime Or both Novel + Fairytale
from the database with logical operational query.
Fetch list for the following combinations :
person who reads only novel(Stored in DB as 1)
person who reads both novel and fairy tale(Stored in DB as 1+2 = 3)
person who reads all the three i.e {novel + fairy tale + bed time} (stored in DB as 1+2+4 = 7)
The count of these are stored in the database in a column called BookType(marked with red in fig.)
How can I fetch the above list using MySQL query
From the example, I need to fetch users like novel readers (1,3,5,7).
The heart of this question is conversion of decimal to binary and mysql has a function to do just - CONV(num , from_base , to_base );
In this case from_base would be 10 and to_base would be 2.
I would wrap this in a UDF
So given
MariaDB [sandbox]> select id,username
-> from users
-> where id < 8;
+----+----------+
| id | username |
+----+----------+
| 1 | John |
| 2 | Jane |
| 3 | Ali |
| 6 | Bruce |
| 7 | Martha |
+----+----------+
5 rows in set (0.00 sec)
MariaDB [sandbox]> select * from t;
+------+------------+
| id | type |
+------+------------+
| 1 | novel |
| 2 | fairy Tale |
| 3 | bedtime |
+------+------------+
3 rows in set (0.00 sec)
This UDF
drop function if exists book_type;
delimiter //
CREATE DEFINER=`root`#`localhost` FUNCTION `book_type`(
`indec` int
)
RETURNS varchar(255) CHARSET latin1
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
begin
declare tempstring varchar(100);
declare outstring varchar(100);
declare book_types varchar(100);
declare bin_position int;
declare str_length int;
declare checkit int;
set tempstring = reverse(lpad(conv(indec,10,2),4,0));
set str_length = length(tempstring);
set checkit = 0;
set bin_position = 0;
set book_types = '';
looper: while bin_position < str_length do
set bin_position = bin_position + 1;
set outstring = substr(tempstring,bin_position,1);
if outstring = 1 then
set book_types = concat(book_types,(select trim(type) from t where id = bin_position),',');
end if;
end while;
set outstring = book_types;
return outstring;
end //
delimiter ;
Results in
+----+----------+---------------------------+
| id | username | book_type(id) |
+----+----------+---------------------------+
| 1 | John | novel, |
| 2 | Jane | fairy Tale, |
| 3 | Ali | novel,fairy Tale, |
| 6 | Bruce | fairy Tale,bedtime, |
| 7 | Martha | novel,fairy Tale,bedtime, |
+----+----------+---------------------------+
5 rows in set (0.00 sec)
Note the loop in the UDF to walk through the binary string and that the position of the 1's relate to the ids in the look up table;
I leave it to you to code for errors and tidy up.
Related
I have below table structure
ITEM
| ID(Auto Inc) | ORG_ID(FK to ORG) | ITEM_ID |
|-----------------|----------------------|-----------------------|
| 1 | 1 | 1 (Initial Val for A) |
| 1 | 2 | 1 (Initial Val for B) |
| 1 | 1 | 2 (Incremented for A) |
ORG
| ID | NAME |
|------|-----------|
| 1 | A |
| 2 | B |
Is there any possibility of using any generator to manage item_id column. This is not id column for ITEM table. Business requirement is to manage item_id sequential for each org.
You may try to insert using the next query:
INSERT INTO item (org_id, item_id)
SELECT #org_id, COALESCE((SELECT 1 + MAX(item_id)
FROM item
WHERE org_id = #org_id), 1)
where #org_id is the value to be inserted.
The problem: it may insert duplicates while concurrent insertions occures.
I have a this type of data:
| company_id | role_id |
| 1 | 1 |
| 2 | 2 |
| 1 | 2 |
Here's my query which selects one company id and passed as an argument role id.
SELECT company_id AS companyId, COUNT(role_id) AS usersNumber
FROM companies
WHERE role_id = :userId
GROUP BY companyId
Where :userId is an argument passed from JPA.
Which produces something like this:
| company_id | passed_role_id_count |
| 1 | 1 |
| 2 | 1 |
What I want to achieve is to have the output like this:
| company_id | first_role_count | second_role_count |
| 1 | 1 | 1 |
| 2 | 0 | 1 |
Is it possible to have the output like this? Or maybe is it better to select all from DB and then group using Java Streams?
Use a filtered aggregation:
SELECT company_id AS companyId,
COUNT(*) filter (where role_id = 1) AS first_role_count,
COUNT(*) filter (where role_id = 2) AS second_role_count
FROM companies
WHERE role_id = :userId
GROUP BY companyId
With the hint from #jarlh I managed to solve my problem:
SELECT eu.company_id,
SUM(CASE WHEN eu.role_id = 2 THEN 1 ELSE 0 END) AS "first_role",
SUM(CASE WHEN eu.role_id = 3 THEN 1 ELSE 0 END) AS "second_role"
FROM users eu
GROUP BY eu.company_id;
I am using Oracle 11g, and I have tables with data and structure as follows:
TABLE1_PARENT:
-------------------
PID | Name | Age |
-------------------
1 | Mark | 35 |
2 | Jane | 40 |
3 | Agatha | 45 |
-------------------
TABLE2_CHILD
==============================================
CID | Name | Age | Class | House | PID |
----------------------------------------------
1 | John | 7 | 3 | Red | 1 |
2 | Marie | 5 | 1 | Yellow| 2 |
3 | Petra | 6 | 2 | Green | 3 |
4 | Taylor | 8 | 4 | Blue | 2 |
5 | Lean | 9 | 5 | Red | 2 |
6 | Justin | 7 | 3 | Yellow| 3 |
7 | Arianna | 5 | 1 | Blue | 3 |
8 | Brendon | 6 | 2 | Green | 3 |
9 | Shawn | 7 | 3 | Red | 1 |
----------------------------------------------
For a single condition, the query is simple:
SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD WHERE AGE=7);
which will result in the following result:
TABLE1_PARENT:
-------------------
PID | Name | Age |
-------------------
1 | Mark | 35 |
3 | Agatha | 45 |
-------------------
However, if I want to fetch the list of parents whose children are of age=7 and belong to house='GREEN', if I write a query as below:
SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD WHERE AGE=7 AND house='GREEN');
I would get no results.
I am expecting the result to be :
TABLE1_PARENT:
-------------------
PID | Name | Age |
-------------------
3 | Agatha | 45 |
-------------------
since Agatha has a child belonging to age=7, and a child belonging to house='GREEN'.
I was able to come up with a solution for a similar data structure using Java streams. I am trying to do the same using Oracle SQL.
List<Parent> filteredParents = parents.stream()
.filter(parent -> parent.getChildren().stream()
.anyMatch(child -> child.getAge().equals("7")) && parent.getChildren().stream()
.anyMatch(child -> child.getHouse().equalsIgnoreCase("Green")))
.collect(Collectors.toList());
I am expecting the query to give me a result where the conditions could match any of the children. Because, the filtering is happening at the Parent level.
Any help would be great. Thanks!
You can do it with EXISTS:
SELECT t.*
FROM TABLE1_PARENT t
WHERE t.PID IN (
SELECT PID FROM TABLE2_CHILD WHERE AGE=7
) AND EXISTS (
SELECT 1 FROM TABLE2_CHILD WHERE PID = t.PID AND House = 'Green'
)
The problem with your query is that it tries to apply both conditions in the same row inside TABLE2_CHILD. But this is not what you want.
You want the parent ids for which children rows have AGE = 7 and there is a row inside TABLE2_CHILD with House = 'Green'.
You could use EXISTS for both conditions, which may be more efficient:
SELECT t.*
FROM TABLE1_PARENT t
WHERE EXISTS (
SELECT 1 FROM TABLE2_CHILD WHERE PID = t.PID AND AGE=7
) AND EXISTS (
SELECT 1 FROM TABLE2_CHILD WHERE PID = t.PID AND House = 'Green'
)
or with conditional aggregation by grouping the child table by PID:
SELECT * FROM TABLE1_PARENT
WHERE PID IN (
SELECT PID
FROM TABLE2_CHILD
GROUP BY PID
HAVING
SUM(CASE WHEN Age = 7 THEN 1 ELSE 0 END) > 0
AND
SUM(CASE WHEN House = 'Green' THEN 1 ELSE 0 END) > 0
)
You are not getting output because in your TABLE2_CHILD, there is no child whose age is 7 in the green house. For your expected result, the query should be:
SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD WHERE AGE=7) AND PID IN (SELECT PID FROM TABLE2_CHILD WHERE house='GREEN');
If you want to get the parent who have a child with age = 7, and the same child belongs to house=GREEN, use the query you already wrote:
SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD IF AGE=7 AND house='GREEN');
If you want to get the parent whose children either has age=7 or house=GREEN or both, use
SELECT * FROM TABLE1_PARENT WHERE PID IN (SELECT PID FROM TABLE2_CHILD IF AGE=7 OR house='GREEN');
I have been searching like forever
I am using min and max for the last and and first record but how do I get the next/ record? I have a column name rowid it is the pk and auto incremented by one every time a user registers
| rowid | Name |
| 1 | John |*
| 2 | Mark |
| 3 | Peter|
| 4 | Help |
so if I click the next button I wanted to select mark which is in rowid 2
| rowid | Name |
| 1 | John |
| 2 | Mark |*
| 3 | Peter|
| 4 | Help |
but if I click the next button twice I want to be in rowid 4
| rowid | Name |
| 1 | John |
| 2 | Mark |
| 3 | Peter|
| 4 | Help |*
how do I do that? by the way I don't have fixed rows since I have a registration function
so here's my code
JButton btnNextLast = new JButton(">>");
btnNextLast.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try{
String sQuery = "select * from accountinfo where rowid = (SELECT MAX(rowid) FROM accountinfo)";
PreparedStatement prst = connection.prepareStatement(sQuery);
ResultSet rs = prst.executeQuery();
lblSID.setText(rs.getString("sid"));
lblfirst.setText(rs.getString("last"));
lblLast.setText(rs.getString("first"));
lblmiddle.setText(rs.getString("middle"));
lblbirth.setText(rs.getString("birth"));
lblcontact.setText(rs.getString("contact"));
}catch(Exception qwe){
}
}
});
I've tried
select rowid
from accountinfo
where rowid >1
order by rowid
limit 1
but no luck
and if I remove order by rowid limit 1. It just show the next record which is 2 and never function again
I have a Table as shown below
+-------------+----------------------+-------------+------+------+------+
| document_id | T1 | T2 | T3 | T4 | T5 |
+-------------+----------------------+-------------+------+------+------+
| 61 | PQR | Burger | NULL | NULL | NULL |
| 66 | Chips And Chocolates | Bummy Chips | NULL | NULL | NULL |
| 69 | Test | Bummy Chips | NULL | NULL | NULL |
+-------------+----------------------+-------------+------+------+------+
I have a Pagination in my screen which got Prev and Next Buttons as shown below
On page load , i am calling a service which does this query and returns me the Result.
select * from vendor_categories ORDER BY document_id ASC Limit 1
Which fetches the First Record from the table and shows that data
My question is that on click of the Next button how can I fetch the next record (I can't rely on document_id or the data because there will be more than one user)
You can use limit and offset. You need to pass the page number as the argument.
select * from vendor_categories ORDER BY document_id ASC offset <:pageNumber> Limit 1