sql select throught join table - sql

Hy all,
I need a little help with writing a select...the problem is the following:
I have the following tables:
help
+----+-------+---------+
| id | title | content |
+----+-------+---------+
| 1 | a | acont |
| 2 | b | bcont |
+----+-------+---------+
helptag
+----+------+
| id | name |
+----+------+
| 1 | atag |
| 2 | btag |
+----+------+
helphelptag(join table)
+--------+-----------+
| helpid | helptagid |
+--------+-----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
+--------+-----------+
I need to select those helps, whish has the ids i give.
So for example if i give tag_id 2, than both help 1 and 2
but if i give tag_id 1 and 2, than only help 1.
I've tried leftjoin, with the ids IN[tag_ids], but it gives back both helps if i give 1 and 2.

This is an example of a "set-within-sets" query. I like to solve this using aggregation and having clause. For your first question:
select helpid
from helphelptag
group by helpid
having sum(case when helptagid = 2 then 1 else 0 end) > 0;
For the second, just add another condition:
having sum(case when helptagid = 2 then 1 else 0 end) > 0 and
sum(case when helptagid = 1 then 1 else 0 end) > 0;
Each condition counts the number of rows that match a given condition.

Related

Count the number of appearances of char given a ID

I have to perform a query where I can count the number of distinct codes per Id.
|Id | Code
------------
| 1 | C
| 1 | I
| 2 | I
| 2 | C
| 2 | D
| 2 | D
| 3 | C
| 3 | I
| 3 | D
| 4 | I
| 4 | C
| 4 | C
The output should be something like:
|Id | Count | #Code C | #Code I | #Code D
-------------------------------------------
| 1 | 2 | 1 | 1 | 0
| 2 | 3 | 1 | 0 | 2
| 3 | 3 | 1 | 1 | 1
| 4 | 2 | 2 | 1 | 0
Can you give me some advise on this?
This answers the original version of the question.
You are looking for count(distinct):
select id, count(distinct code)
from t
group by id;
If the codes are only to the provided ones, the following query can provide the desired result.
select
pvt.Id,
codes.total As [Count],
COALESCE(C, 0) AS [#Code C],
COALESCE(I, 0) AS [#Code I],
COALESCE(D, 0) AS [#Code D]
from
( select Id, Code, Count(code) cnt
from t
Group by Id, Code) s
PIVOT(MAX(cnt) FOR Code IN ([C], [I], [D])) pvt
join (select Id, count(distinct Code) total from t group by Id) codes on pvt.Id = codes.Id ;
Note: as I can see from sample input data, code 'I' is found in all of Ids. Its count is zero for Id = 3 in the expected output (in the question).
Here is the correct output:
DB Fiddle

Update specific column with the value of single column from another table

I want to update the specific column with value of a single column from another table using sql query.
The specific column I want to update is in the WorkingTime table. Like for example I want to update its value by 1 depending on its IDNo and Date from TABLE 2
WorkingTime table:
IDNo | PeriodDate | SPLP | NVLP | NBLP | PLP | BLP | MLP | SLP | VLP | NSLP |
18-031 |06/11/2017 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
18-032 |06/12/2017 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
18-033 |06/13/2017 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
And the name of the column I want to update in WorkingTime is in the LeaveDetails. The column with the name LeaveType.
LeaveDetails:
Contro | IDNo | LeaveType| DateFrom | DateTo | NoOfDays |
000041 |18-031 | SPLP |06/11/2019|06/11/2019| 1 |
000042 |18-032 | NVLP |06/12/2019|06/12/2019| 1 |
000043 |18-033 | PLP |06/13/2019|06/13/2019| 1 |
And my expected result after the query is this
Expected result:
IDNo | PeriodDate | SPLP | NVLP | NBLP | PLP | BLP | MLP | SLP | VLP | NSLP |
18-031 |06/11/2017 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
18-032 |06/12/2017 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
18-018 |06/13/2017 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
Can anyone please help me with the query i will use to make this happen. Thank you in advance.
I'm unclear which tables/columns you are trying to update but you can update a column value in one table using the column value of a different table by using a sub query, for example:
UPDATE TABLE_1
SET LEAVETYPE =
(SELECT NEW_COLUMN FROM TABLE_2 WHERE PRIMARY_KEY = 'Something')
WHERE PRIMARY_KEY = 'Something'
;
Try to Use temp table. first take your data in temp table then update main table by using temp table data.
Or using join the table
update u
set u.assid = s.assid
from ud u
inner join sale s on
u.id = s.udid
One method is a series of case expressions and subqueries:
update table1
set splp = (case when exists (select 1
from table2 t2
where t2.idno = table1.idno and
t2.perioddate = t1.perioddate and
t2.leavetype = 'SPLP'
)
then 1 else table1.splp
end),
splp = (case when exists (select 1
from table2 t2
where t2.idno = table1.idno and
t2.perioddate = t1.perioddate and
t2.leavetype = 'NVLP'
)
then 1 else table1.nvlp
end),
. . .;
Depending on the database, there are other approach as well, but the above should work in any database.

Returning rows with the same ID but exclude some on second column

I've seen similar questions about but not quite hitting the nail on the head for what I need. Lets say I have a table.
+-----+-------+
| ID | Value |
+-----+-------+
| 123 | 1 |
| 123 | 2 |
| 123 | 3 |
| 456 | 1 |
| 456 | 2 |
| 456 | 4 |
| 789 | 1 |
| 789 | 2 |
+-----+-------+
I want to return DISTINCT IDs but exclude those that have a certain value. For example lets say I don't want any IDs that have a 3 as a value. My results should look like.
+-----+
| ID |
+-----+
| 456 |
| 789 |
+-----+
I hope this makes sense. If more information is needed please ask and if this has been answered before please point me in the right direction. Thanks.
You can use group by and having:
select id
from t
group by id
having sum(case when value = 3 then 1 else 0 end) = 0;
The having clause counts the number of "3"s for each id. The = 0 returns only returns groups where the count is 0 (i.e. there are no "3"s).
You can use not exists :
select distinct t.id
from table t
where not exists (select 1 from table t1 where t1.id = t.id and t1.value = 3);
Try this:
select id from tablename
group by id
having (case when value=3 then 1 else 0 end)=0
You can also use EXCEPT for comparing following two data sets that will give the desired result set
select distinct Id from ValuesTbl
except
select Id from ValuesTbl where Value = 3

Microsoft Access query to duplicate ROW_NUMBER

Obviously there are a bunch of questions about ROW_NUMBER in MS Access and the usually response is that it does not exist but instead to use a COUNT(*) to create something similar. Unfortunately, doing so does not give me the results that I need.
My data looks like:
RID | QID
---------
1 | 1
1 | 2
1 | 3
1 | 3
2 | 1
2 | 2
2 | 2
What I am trying to get at is a unique count over RID and QID so that my query output looks like
RID | QID | SeqID
------------------
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
1 | 3 | 2
2 | 1 | 1
2 | 2 | 1
2 | 2 | 2
Using the COUNT(*) I get:
RID | QID | SeqID
------------------
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
1 | 3 | 3
2 | 1 | 1
2 | 2 | 2
2 | 2 | 2
My current query is:
SELECT
d.RID
,d.QID
,(SELECT
COUNT(*)
FROM
Data as d2
WHERE
d2.RID = d.RID
AND d2.QID < d.QID) + 1 AS SeqID
FROM
Data as d
ORDER BY
d.RID
,d.QID
Any help would be greatly appreciated.
As Matt's comment implied, the only way to make this work is if you have some column in your table that can uniquely identify each row.
Based on what you have posted, you don't seem to have that. If that's the case, consider adding a new auto increment numeric column that can serve that purpose. Let's pretend that you call that new column id.
With that in place, the following query will work:
select t.rid, t.qid,
(select count(*)
from data t2
where t2.rid = t.rid
and t2.qid = t.qid
and t2.id <= t.id) as SeqID
from data t
order by t.rid, t.qid
SQLFiddle Demo

Count within the result set of a subquery

I have the following relations in my database:
Invoice InvoiceMeal
--------------------- ---------------------------
| InvoiceId | Total | | Id | InvoiceId | MealId |
--------------------- ---------------------------
| 1 | 22.32 | | 1 | 1 | 3 |
--------------------- ---------------------------
| 2 | 12.18 | | 2 | 1 | 2 |
--------------------- ---------------------------
| 3 | 27.76 | | 3 | 2 | 2 |
--------------------- ---------------------------
Meal Type
----------------------------------- -------------------
| Id | Name | TypeId | | Id | Name |
----------------------------------- -------------------
| 1 | Hamburger | 1 | | 1 | Meat |
----------------------------------- -------------------
| 2 | Soja Beans | 2 | | 2 | Vegetarian |
----------------------------------- -------------------
| 3 | Chicken | 2 |
-----------------------------------
What I want to query from the database is InvoiceId and Total of all Invoices which consist of at least two Meals where at least one of the Meals is of Type Vegetarian. I have the following SQL query and it works:
SELECT
i."Id", i."Total"
FROM
public."Invoice" i
WHERE
(SELECT COUNT(*)
FROM public."InvoiceMeal" im
WHERE im."InvoiceId" = i."Id" AND
(SELECT COUNT(*)
FROM public."Meal" m, public."Type" t
WHERE im."MealId" = m."Id" AND
m."TypeId" = t."Id" AND
g."Name" = 'Vegetarian') > 0
) >= 2;
My problem with this query is that I can not easily modify the condition that there must at least one vegetarien Meal. I want to be able, for example, to change it to at least two vegetarian meals. How can I achieve this with my query?
I would approach this by joining the tables together and using aggregation. The having clause can handle the conditions:
select i.Id, i.Total
from InvoiceMeal im join
Invoice i
on i.InvoiceId = im.InvoiceId join
Meal m
on im.mealid = m.mealid join
Type t
on m.typeid = t.typeid
group by i.Id, i.Total
having count(distinct im.mealid) >= 2 and
sum(case when t.name = 'Vegetarian' then 1 else 0 end) > 0;
I also see no reason to put double quotes around column names. That just makes the query harder to write and read.