Fetching data in one query from mapping table - java

I want to fetch the data from following tables such that i do not have to call multiple queries and set the attribute of response isLikedByUser. userId i am sending in the request.
Posts -- Table Name
userId,
postId,
text,
likesCount,
commentsCount
LikeMapping -- Table Name
userId,
postid
Now I wrote query and fetched data from first table based on userId. Then iterated on each row and for each postId and userId from request found rows in Table 2 and if data is found I set the attribute of isLikedByUser.
How can I write the query which can help me to fill the attribute value without writing query in loop.
Thanks
To clarify more isLikedByUser is only the response attribute no column in any table and want to set it as true or false if mapping is found in second table.

Use a LEFT JOIN on a sub-query together with COALESCE to get a true/false (1/0) flag if the user has liked own post or not for each post by the given user
SELECT p.*, COALESCE(isLikedByUSer, 0)
FROM Posts p
LEFT JOIN (SELECT 1 isLikedByUser, postId, userID FROM LikeMapping) as l ON l.postId = p.postId AND l.userId = p.userId
WHERE p.userId = 100

You need to use LEFT OUTER JOIN and CASE statement. Something like below should work.
Select p.*,
case count(lm.postid) when 0 then true else false end as isLikedByUser
from Posts p
LEFT OUTER JOIN LikeMapping lm ON p.postId = lm.postId
WHERE lm.userId = userIdFromRequest
group by userId, postId, text, likesCount, commentsCount;

This might be faster than the other Answers.
SELECT p.*,
lm.postid IS NOT NULL AS isLikedByUser
FROM Posts AS p
LEFT JOIN ( SELECT DISTINCT postid FROM LikeMapping ) AS lm
ON lm.postid = p.postid
What version of MySQL? This probably needs 5.6 or later.
Please provide EXPLAIN SELECT ... if you wish to discuss further.

Related

Do not join 2 tables but paging with them

I have two oracle table:users and logs,as follow,
users:
---------
id number,
name varchar2(50)
logs:
-----
user_id number,
visit_date date
I need to find out the first 10 users who never appears in the logs table (means they never visit the page),I can write a sql:
select *
from users u
where not exists (
select 1 from logs o
where o.user_id = u.id)
and rownum<=10
But now the problem is these two table are not in the same schema,they could not be accessed for each other,so I can not join them.
Because there are two microservices,one microservice should query its own schema
If I fetch 10 records from users,maybe they all never visit the page,I need to fetch 10 more,then after that still 5 users did not visit that page,I need to fetch 5 more,and so on.So I am not sure how many record I should fetch at the first time.Is it a good idea to do so?And how to write the code?
If I fetch all the record of the 2 tables,then do join using Java code,I'm worried about the amount of data being too large.Or should I just make these two tables accessible to each other?
So,how to do paging with 2 table but not join them?
But now the problem is these two table are not in the same schema,they could not be accessed for each other,so I can not join them.
Create a user that can see both schemas and log in to that user and access the tables using schema_name.table_name:
SELECT *
FROM schema1.users u
WHERE NOT EXISTS (
SELECT 1
FROM schema2.logs l
WHERE l.user_id = u.id
)
ORDER BY u.something
FETCH FIRST 10 ROWS ONLY
or
SELECT *
FROM (
SELECT *
FROM schema1.users u
WHERE NOT EXISTS (
SELECT 1
FROM schema2.logs l
WHERE l.user_id = u.id
)
ORDER BY u.something
)
WHERE ROWNUM <= 10
Alternatively, create a third schema and GRANT the SELECT privilege on the USERS and LOGS tables in the first two schemas and then create a view in that third schema and a new micro-service and use that.

Select statements, Joins, and Repurpose Query in SQL

I have a constant set of users that I want to filter out and apply to each query to look at what they are doing on an app. I have been poking and probing around here to get a better sense of how to do this, but it is still unclear to me. I am a newbie with SQL statements and JAVA. Any help, particularly explanation is highly welcomed.
I have been trying to figure it out using these two articles to no avail: 1 & 2; these examples show how you can create a query and use it in another query, which is what I am trying to do.
Someone mentions a wrap (see ref. 1) which is what i attempt to do:
Sure, wrap your two set operations in outer queries with selects that include fixed columns called Source, i.e. SELECT
'horrible_query_1' AS Source, * and SELECT 'ugly_query_2' AS Source,
*.
That way your UNION will give you all the columns from your query plus the source identifier.
My question: is it possible to repurpose these queries into separate queries without having to do joins with the variable? I don't understand how that works (I'm not sure I am saying it right either).
This is the User group and filter I want to repurpose across all queries:
<select id="get_num_x_users" resultClass="java.lang.Integer">
select count(distinct user_id) from positions sp
join position_definitions sd on sp.position_id = sd.id
where sd.position like '%catcher%'
or lower(sd.position) like '%pitcher%'
or lower(sd.position) like '%dh%';
</select>
Repurpose into this query (among a few others):
<select id="get_u_counts" resultClass="java.lang.Integer">
SELECT COUNT(DISTINCT u.id)
FROM searches s
JOIN users u
ON s.user_id = u.id
WHERE search_date > DATE_SUB(curdate(), INTERVAL 3 MONTH)
AND LENGTH(search_term) > 0
AND search_term NOT LIKE ' LIC: SPEC: %'
AND u.type != 'coach';
</select>
My attempt (That does not work when I am in mysql database):
with get_x_users as (
select count(distinct user_id) from positions sp
join position_definitions sd on sp.position_id = sd.id
where sd.position like '%catcher%'
or lower(sd.position) like '%pitcher%'
or lower(sd.position) like '%dh%';),
(SELECT COUNT(get_x_users)
FROM searches s
JOIN users u
ON s.user_id = u.id
AND get_x_users
WHERE search_date > DATE_SUB(curdate(), INTERVAL 3 MONTH)
AND LENGTH(search_term) > 0
AND u.type != 'coach');
In SQL we can join tables together using a common field. For instance, if you have a user_id field in two different tables you can match the records using that common field. You can also create a join that gives you all the records in one table and only those that match in the second table, that's what LEFT JOIN does.
Using this principle, you do a little reverse logic and create a query which gives you all the records from your search query (ExcludeQuery) and join it to the users whom you want to exclude. This will give you a list of records with and without matches to the excluded users. What you do then is use a where to only include the records that haven't matched an excluded user, WHERE ExcludeQuery.user_id IS NULL.
SELECT s.*
FROM searches s
JOIN users u
ON s.user_id = u.id
WHERE search_date > DATE_SUB(curdate(), INTERVAL 3 MONTH)
AND LENGTH(search_term) > 0 AND u.type != 'coach'
LEFT JOIN
(select user_id from positions sp
join position_definitions sd on sp.position_id = sd.id
where sd.position like '%catcher%'
or lower(sd.position) like '%pitcher%'
or lower(sd.position) like '%dh%') AS ExcludeQuery
ON ExcludeQuery.user_id=s.user_id
WHERE ExcludeQuery.user_id IS NULL

How to separate between data selecting from multiple tables?

I want to search in 16 different tables, but I don't wanna repeat the "select from DB" 16 times; I think that's not really help in performance!!!
I am using:
query="SELECT * FROM table1, table2,..., table16 WHERE id=?";
Is it correct ??
my problem is how to separate between data of tables ??
also maybe I can get from one table two or more results for one "id"; So I want to know which data is from which table !!
.
Best regards,
Your query will not work, because you are trying to join those multiple tables, whereas what you want to do is search (filter) those 16 tables.
You could use a union all to do this in a single query:
select xxx, 'table1' as source_table
from table1
where id = ?
union all
select xxx, 'table2' as source_table
from table2
where id = ?
and so on. The second derived field source_table can be used to determine which table returned which result.
You have to list all fields using aliases for fields with same name, and prefix with table names.
For example :
query = "SELECT table1.id as id_1, table2.id as id_2, ... WHERE id_1 = 23"
Probably a very long query to write, but you have solution to generate and paste it : You can do this for example with FlySpeed SqlQuery (free for personal use)
FlySpeed SqlQuery will generate all aliases for you, and automatically prefix with table names.
A little clarification would help. If all 16 tables have the same fields and you want them in a continuous list, you can use UNION as suggested above. On the other hand, if there are only a few fields that match and you want to compare the values for each table side-by-side, you'll want to use joins and provide aliases with the table names, as also suggested above.
However, looking at the snippet of code you've provided, I'm going to guess that you're either building some kind of stored procedure or else implementing SQL in some other language. If that's the case, how about loading your table names into an array and using a for loop to build the query, such as the following psuedo-code:
tableList = ["table1", "table2"...]
fieldnames = ["field1", "field2"...]
query = "SELECT "
for i = 0 to count(tableList):
for j = 0 to count(fieldnames):
query = query + tablelist[i] + "." + fieldnames[j] + ", "
j++
i++
query = query + "FROM "
for i = 0 to count(tableList):
query = query + tableList[i] + ", "
i++
query = query + "WHERE " ...
And so forth. Much of this depends on what exactly you're looking to do, how often you're looking to do it, and how often the variables (like which tables or fields you're using) are going to change.

How to select count(*) from many to many in spring data jpa?

I have two tables (for example posts:tags) with M:N relationship with standard middle table.
I want to select all post ids with the count of tags per each post with spring data jpa.
Here is what i did:
SELECT p.id, count(t) as total FROM post p join p.tags t;
However this is not returning the correct result.
Fixed it, adding group by did the trick.
SELECT p.id, count(t) as total
FROM post p join p.tags t
GROUP BY p.id;

SQL for return all the id which does not exist in db and passing in sql

I need some help writing an SQL statement for the below requirement.
I have list of employee_id which I need to check whether they are exist in the DB or not from the java layer I want to use one query for this.
Sample query:
SELECT *
FROM employee
WHERE employee_id IN (1001,1002,1002,10000004).
In this query 10000004 does not exist in DB.
One approach in my mind is to use the below query:
SELECT Count(employee_id)
FROM employee
WHERE employee_id IN (1001,1002,1002,10000004).
Then check the list size and the result from the query in java layer. But I don’t want this because I need all those employee_id which does not exist in DB.
declare #employeeids varchar(1000) --to store ids as comma seperated string
declare #tmpEmployee table (employee_id varchar(50)) --temp employee table to store ids from string
declare #pointer int
select #employeeids = '1001,1002,1002,10000004' --list of ids to check against database
while (charindex(',', #employeeids, 0) > 0)
begin
set #pointer = charindex(',', #employeeids, 0)
insert into #tmpEmployee (employee_id)
--remove white spaces if exists
select ltrim(rtrim(substring(#employeeids, 0, #pointer)))
set #employeeids = stuff(#employeeids, 1, #pointer, '')
end
insert into #tmpEmployee (employee_id)
select ltrim(rtrim(#employeeids))
select r.employee_id -- required ids which does not exists in database
,e.employee_id
from #tmpEmployee r
left join employee e on r.employee_id=e.employee_id
where e.employee_id is null
If you are using Oracle, then this link may help you. It's all about usage of built in SYS.DBMS_DEBUG_VC2COLL function
Exist a very bad way to do that is this:
SELECT * FROM (SELECT 5930 id UNION SELECT 8109 id
UNION SELECT 8110 id UNION SELECT 8115 id UNION SELECT 8112 id
UNION SELECT 8113 id UNION SELECT -1 id) b
WHERE b.id NOT IN (SELECT f.id FROM employee f)
I recommed you do that in other way.

Categories