select rows from table based on data from another table - asp.net

Mentor table
------------
name (varchar)
contact (int)
english (boolean)
french (boolean)
german (boolean)
Student table
-------------
name (varchar)
contact (int)
english (boolean)
french (boolean)
german (boolean)
I want to match mentor with student based on the languages, such that for example:
if mentor1 knows english and french, he will be matched with all students that know at least english or french.
mentor1 (english, french)
-------------------------
studentA (english);
studentB (english, french);
studentC (english, german);
studentD (english, french, german)
if mentor2 know german only, he will be matched with all students that know at least german. the students matched can know more than just german.
mentor2 (german)
----------------
studentC (english, german)
studentD (english, french, german)
normally i will just use a bunch of if then else to piece together a sql string but i am using gridview to display the data so i am not sure what can i do.
sample codes and tutorials are alway welcome.
edit: forgot to mention that the mentor table will also have columns such as name and contact. so the output on the gridview should be 1 row per mentor.

Select
m.MentorName
, m.Language
, s.StudentName
from Mentor as m
inner join Student as s
on (m.English = 1 and m.English = s.English)
or (m.french = 1 and m.French = s.French)
or (m.German = 1 and m.German = s.German);
This would be easier if you had your tables structured without field for each language but a record instead
Table: Mentor(MentorName, Language)
Rows:
Mentor1 | English
Mentor2 | Englisn
Mentor2 | French
Do the same for Students and then the query is:
Select
m.MentorName
, m.Language
, s.StudentName
from Mentor as m
inner join Student as s
on m.Language = s.Language
The benefit here is if you add another language, it is purely data entry and no need to change table structure or your code, but that is not always an option.

SELECT m.*, s.name
FROM dbo.Mentor m
JOIN dbo.Student s
ON EXISTS
(
SELECT x.LanguageID
FROM
(
SELECT 1 AS LanguageID WHERE s.english = 1 UNION ALL
SELECT 2 AS LanguageID WHERE s.french = 1 UNION ALL
SELECT 3 AS LanguageID WHERE s.german = 1
) x
INTERSECT
SELECT y.LanguageID
FROM
(
SELECT 1 AS LanguageID WHERE m.english = 1 UNION ALL
SELECT 2 AS LanguageID WHERE m.french = 1 UNION ALL
SELECT 3 AS LanguageID WHERE m.german = 1
) y
)
ORDER BY m.name

Related

How to assign a 0 for count if the value doesnt exist in the table

I have a table of ratings
|EMPLOYEE|Rating|
1 B
2 B
3 C
4 NULL
5 NULL
6 NULL
and i want to retrieve the count of the grades by each grading like so
Result set
|Rating|Count|
A 0
B 2
C 1
D 0
E 0
I used this query but the grades that isnt in the table will jsut appear as null
select rating,count(rating) from table group by rating
I also used this query which is basically a pivot of the above result set but for some reason it shows 3 rows of repeating data instead of just 1
select (select count(rating) from table where rating = 'E'),(select count(rating) from table where rating = 'D'),(select count(rating) from table where rating = 'C'),(select count(rating) from table where rating = 'B'),(select count(rating) from table where rating = 'A') from table group by rating
If you had a table for the assignable ratings then it would be quite simple (and flexible)
e.g. consider :-
Your existing table.
DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (employee TEXT, rating text);
INSERT INTO mytable VALUES (1,'B'),(2,'B'),(3,'C'),(4,null),(5,null),(6,null);
The rating table.
DROP TABLE IF EXISTS rating;
CREATE TABLE IF NOT EXISTS rating (rating);
INSERT INTO rating VALUES('A'),('B'),('C'),('D'),('E');
Then :-
SELECT rating.rating, (SELECT count(*) FROM mytable WHERE rating.rating = mytable.rating) FROM rating;
Results in :-
Flexibility
Add some new ratings e.g. as per :-
INSERT INTO rating VALUES('X'),('Y'),('Z');
And then run:--
SELECT rating.rating, (SELECT count(*) FROM mytable WHERE rating.rating = mytable.rating) FROM rating;
results in :-

Cannot replace a string with several random strings taken from another table in sqlite

I'm trying to replace a placeholder string inside a selection of 10 random records with a random string (a name) taken from another table, using only sqlite statements.
i've done a subquery in order to replace() of the placeholder with the results of a subquery. I thought that each subquery loaded a random name from the names table, but i've found that it's not the case and each placeholder is replaced with the same string.
select id, (replace (snippet, "%NAME%", (select
name from names
where gender = "male"
) )
) as snippet
from imagedata
where timestamp is not NULL
order by random()
limit 10
I was expecting for each row of the SELECT to have different random replacement every time the subquery is invoked.
hello i'm %NAME% and this is my house
This is the car of %NAME%, let me know what you think
instead each row has the same kind of replacement:
hello i'm david and this is my house
This is the car of david, let me know what you think
and so on...
I'm not sure it can be done inside sqlite or if i have to do it in php over two different database queries.
Thanks in advance!
Seems that random() in the subquery is only evaluated once.
Try this:
select
i.id,
replace(i.snippet, '%NAME%', n.name) snippet
from (
select
id,
snippet,
abs(random()) % (select count(*) from names where gender = 'male') + 1 num
from imagedata
where timestamp is not NULL
order by random() limit 10
) i inner join (
select
n.name,
(select count(*) from names where name < n.name and gender = 'male') + 1 num
from names n
where gender = 'male'
) n on n.num = i.num

SQlite multiple IDs linking one to another table

I have one table containing rows with information about dealers and unique IDs.
id name
1 dealer1
2 dealer2
The other table contains products which are sometimes available at multiple dealers.
name dealerids
product1 1, 2
product2 2
Now I would like to query all dealers a product is available at, but I don't know how. I tried something like:
SELECT * FROM dealers WHERE id IN (SELECT dealerids FROM products WHERE name = "product1")
which didn't work. I'm in C# and dealerids is based on a string and stored as TEXT in the database. I tried "'1', '2'" and "1, 2", both didn't work for me.
I'm quiet new to SQL so is there a way to achieve what I want using the TEXT datatype?
Well, that's strange way to store the values in a database - as a string separated by commas. But if it's really the case and you can not change this to multiple lines where each record corresponds to one dealer id , you probably can try this:
select * from dealers where exists (select 1 from products where name = "product1" and dealerids like
dealers.id || ',' || '%') or exists
(select 1 from products where name = "product1" and dealerids like '%' || ', ' || dealers.id || ',%')
or exists
(select 1 from products where name = "product1" and dealerids like '%, ' || dealeris.id)
The first clause is taking care of the case where desired delearid is the first one in the string, the second clause is for the case when it's in the middle, and the third one is for the ending id.
A normalized database would look something like this, in your scenario.
// table_dealer
id name
1 dealer1
2 dealer2
// table_product
id title
1 product1
2 product2
//table_associate
id product_id dealer_id
1 1 1
1 2 1
Now I would like to query all dealers a product is available at, but I don't know how. I tried something like
//searching by product_id
select dealer_id from table_associate where product_id = X
Use JOIN query to get data from these 3 tables.

Counting 2 Columns from Separate Tables Between 2 Dates

I have a query that Counts 2 columns from 2 separate tables using subqueries, which works. Now I have to implement into this query the ability to filter out these results based on the Date of a Call Record. I will post the query in which I am working with:
SELECT (m.FirstName || " " || m.LastName) AS Members,
(
SELECT count(CallToLineOfficers.MemberID)
FROM CallToLineOfficers
WHERE CallToLineOfficers.MemberID = m.MemberID
)
+ (
SELECT count(CallToMembers.MemberID)
FROM CallToMembers
WHERE CallToMembers.MemberID = m.MemberID
) AS Tally
FROM Members AS m, Call, CallToMembers, CallToLineOfficers
Join Call on CallToMembers.CallID = Call.CallID
and CallToLineOfficers.CallID = Call.CallI
WHERE m.FirstName <> 'None'
-- and Call.Date between '2017-03-21' and '2017-03-22'
GROUP BY m.MemberID
ORDER BY m.LastName ASC;
Ok, so table Call stores the Date and its PK is CallID. Both CallToLineOfficers and CallToMembers are Bridge Tables that also contain only CallID and MemberID. With the current query, where the Date is commented out, that Date range should only return all names, but a count of 1 should appear under 1 person's name.
I have tried joining Call.CallID with both Bridge Tables' CallIDs without any luck, though I think this is the right way to do it. Could someone help point me in the right direction? I am lost. (I tried explaining this the best I could, so if you need more info, let me know.)
UPDATED: Here is a screenshot of what I am getting:
Based on the provided date in the sample, the new results, with the Date, should be:
Bob Clark - 1
Rob Catalano - 1
Matt Butler - 1
Danielle Davidson - 1
Jerry Chuska - 1
Tom Cramer - 1
Everyone else should be 0.
At the moment, the subqueries filter only on the member ID. So for any member ID in the outer query, they return the full count.
To reduce the count, you have to filter in the subqueries:
SELECT (FirstName || " " || LastName) AS Members,
(
SELECT count(*)
FROM CallToLineOfficers
JOIN Call USING (CallID)
WHERE MemberID = m.MemberID
AND Date BETWEEN '2017-03-21' AND '2017-03-22'
)
+ (
SELECT count(*)
FROM CallToMembers
JOIN Call USING (CallID)
WHERE MemberID = m.MemberID
AND Date BETWEEN '2017-03-21' AND '2017-03-22'
) AS Tally
FROM Members AS m
WHERE FirstName <> 'None'
ORDER BY LastName ASC;

How to specify where clause with at least x values from nested select

Suppose I have these tables:
person
id name
-- ----
1 dude
2 john
3 doe
...etc
favourite_food
personid food
-------- ------
1 apples
5 apples
5 oranges
And I want to get a list of the names of people who like at least the foods that person 5 likes. Something like below:
SELECT p.name FROM person p
LEFT JOIN favourite_food ff ON ff.personid = p.id
WHERE ff.food = (SELECT food FROM favourite_food WHERE personid = 5)
AND ff.personid <> 5;
Except I have no idea how to specify the 'at least' part. Do I have to create a temporary table or so?
SQL essentially works with sets, so it often helps to reformulate your problem strictly in terms of set theory.
"At least" could be reformulated this way:
If we look only at foods that are favourite foods of person 5, which persons have the same number of favourite foods as person 5?
SELECT name
FROM person
WHERE id IN (SELECT personid
FROM favourite_food
WHERE food IN (SELECT food
FROM favourite_food
WHERE personid = 5)
GROUP BY personid
HAVING COUNT(food) = (SELECT COUNT(food)
FROM favourite_food
WHERE personid = 5)
)
Alternatively, use this reformulation:
We do not want persons who do not like a food that person 5 likes.
Therefore, find all persons for which no food exists that is liked by person 5 but not liked by that person:
SELECT name
FROM person
WHERE NOT EXISTS (SELECT 1
FROM favourite_food AS person5_food
WHERE personid = 5
AND NOT EXISTS (SELECT 1
FROM favourite_food
WHERE personid = person.id
AND food = person5_food.food)
)
(Actually, SQL is based on the relational algebra, and the operation you want is called division.)

Resources