how to update parent table twice if child table return two same id of parent table in mysql using IN - sql

This is the query I'm using, it's working fine but the problem is if (select u.ChannelId from u) return twice the same id of a channelInfo, IN function only update ChannelInfo.Amount once, but it has to minus Amount twice.
For example, if (select u.ChannelId from u) return like this (3, 3), it has to minus ChannelInfo.Amount twice, but it's only minus it once.
How I can solve this problem, can anyone help me, please
ChannelInfo table has one to many relation with Reporting, so in Reporting table can have 2 or 3 ChannelInfo id
with u as (
update "Reporting"
set "Status" = 'run'
where "Status" = 'a'
RETURNING "ChannelId"
)
update "ChannelInfo"
set "Amount"= (CASE WHEN "Duration" = '60' THEN "Amount" - 12.25 ELSE "Amount" - 6.13 END)
where "id" in (select u.ChannelId from u);

I'm not 100% sure what you are asking for, but I think it is to subtract the count of the rows in u from the amount. That is, the constant would be multiplied by a count.
You can use a join to get a count and use that for the calculation:
with u as (
update "Reporting"
set "Status" = 'run'
where "Status" = 'a'
RETURNING "ChannelId"
)
update "ChannelInfo" ci
set "Amount"= (CASE WHEN ci."Duration" = '60' THEN ci."Amount" - uc.cnt * 12.25 ELSE ci."Amount" - uc.cnt * 6.13 END)
from (select u.ChannelId, count(*) as cnt
from u
group by u.ChannelId
) uc
where ci."id" = uc.ChannelId;

Related

Solved: Multiplying the result of a SUM() on one table by the result of a COUNT() from another table

I'm trying to multiply the sum computed in one table by the count of values found in another table linked to it.
I have a table with entries like this:
Table_A
Id
SubId
Start
Stop
For each Id there can be several SubId. The Id is linked through a whole series of other tables to a second table which basically looks like this:
Table_B
Id
Val
Id in Table_B can occur from one to multiple times.
The idea is that I want to mulitply the result of the sum of time spans found in Table_A for each SubId by the count of distinct Val found in Table_B by linking it through the Id.
I already have the sum of time spans from Table_A like this (I'm no developper so it might be very shoddy code, I apologize in advance):
SELECT SUM(duration) FROM (
SELECT (mod_stop - mod_start) AS duration FROM (
SELECT
(CASE
WHEN date_start < '#begin' THEN '#begin'
ELSE date_start
END) AS mod_start,
(CASE
WHEN date_stop > '#end' THEN '#end'
WHEN date_stop = '0' THEN '#end'
ELSE date_stop
END) AS mod_stop
FROM table_a
WHERE (
state = 'Launching' OR
state = 'Running' OR
state = 'Finishing'
)
AND table_a_id IN (
SELECT
DISTINCT(table_a_id)
FROM table_a
WHERE
(to_timestamp(date_start), to_timestamp(date_stop)) OVERLAPS (to_timestamp('#begin'), to_timestamp('#end'))
AND
(state = 'Running' OR state = 'Launching' OR state = 'Finishing')
AND
NOT date_stop = '0'
)
) AS t
) AS d
;
This works but I now need to multiply each duration by the number of Val associated to it's Id and I can't work out how to do this.
I thought having another AND ... IN clause in the WHERE with all the table linking mechanisms returning the individual Val count would do it but the query does not return anything despite running for over an hour whereas without it it returns in approximately ten minutes (there is no index on date_* and Table_A is several tens of million records long which explains why it is so slow) so I fear I might have got something wrong.
Is there a way to do this? Thanks!
Thanks to the comments posted and what I managed to find I've cobbled a solution together. It might be crude but it works. I build a temp table whose values I use to build a CTE. Feel free to comment if you think this can be done better.
BEGIN;
CREATE TEMP TABLE my_jsl ON COMMIT DROP AS
SELECT job_id, job_state, mod_start, mod_stop, duration FROM (
SELECT job_id, job_state, mod_start, mod_stop, mod_stop - mod_start duration FROM (
SELECT job_id, job_state,
(CASE
WHEN date_start < :my_begin THEN :my_begin
ELSE date_start
END) AS mod_start,
(CASE
WHEN date_stop > :my_end THEN :my_end
WHEN date_stop = '0' THEN :my_end
ELSE date_stop
END) AS mod_stop
FROM job_state_logs
WHERE (
job_state = 'Launching' OR
job_state = 'Running' OR
job_state = 'Finishing'
)
AND job_state_log_id IN (
SELECT
DISTINCT(job_state_log_id)
FROM job_state_logs
WHERE
(to_timestamp(date_start), to_timestamp(date_stop)) OVERLAPS (to_timestamp(:my_begin), to_timestamp(:my_end))
AND
(job_state = 'Running' OR job_state = 'Launching' OR job_state = 'Finishing')
AND
NOT date_stop = '0'
)
) AS job_temp_log
) AS job_log
;
WITH my_jr AS (
SELECT COUNT(a.resource_id) jrc, j.job_id
FROM assigned_resources a
INNER JOIN moldable_job_descriptions m ON m.moldable_id = a.moldable_job_id
INNER JOIN jobs j ON j.assigned_moldable_job = m.moldable_id
WHERE j.job_id IN (
SELECT DISTINCT(job_id) FROM my_jsl
)
GROUP BY j.job_id
),
my_surf AS (
SELECT my_jr.job_id, my_jsl.duration, my_jr.jrc, (my_jsl.duration * my_jr.jrc) AS surface
FROM my_jr, my_jsl
WHERE my_jr.job_id = my_jsl.job_id
)
SELECT SUM(surface) job_surface FROM my_surf
;
COMMIT;
;

I just started learning SQL and I couldn't do the query, can you help me?

There is a field in the sql query that I can't do. First of all, a new column must be added to the table below. The value of this column needs to be percent complete, so it's a percentage value. So for example, there are 7 values from Cupboard=1 shelves. Where IsCounted is here, 3 of them are counted. In other words, those with Cupboard = 1 should write the percentage value of 3/7 as the value in the new column to be created. If the IsCounted of the others is 0, it will write zero percent. How can I do this?
My Sql Code:
SELECT a.RegionName,
a.Cupboard,
a.Shelf,
(CASE WHEN ToplamSayım > 0 THEN 1 ELSE 0 END) AS IsCounted
FROM (SELECT p.RegionName,
r.Shelf,
r.Cupboard,
(SELECT COUNT(*)
FROM FAZIKI.dbo.PM_ProductCountingNew
WHERE RegionCupboardShelfTypeId = r.Id) AS ToplamSayım
FROM FAZIKI.dbo.DF_PMRegionType p
JOIN FAZIKI.dbo.DF_PMRegionCupboardShelfType r ON p.Id = r.RegionTypeId
WHERE p.WarehouseId = 45) a
ORDER BY a.RegionName;
The result is as in the picture below:
It looks like a windowed AVG should do the trick, although it's not entirely clear what the partitioning column should be.
The SELECT COUNT can be simplified to an EXISTS
SELECT a.RegionName,
a.Cupboard,
a.Shelf,
a.IsCounted,
AVG(a.IsCounted * 1.0) OVER (PARTITION BY a.RegionName, a.Cupboard) Percentage
FROM (
SELECT p.RegionName,
r.Shelf,
r.Cupboard,
CASE WHEN EXISTS (SELECT 1
FROM FAZIKI.dbo.PM_ProductCountingNew pcn
WHERE pcn.RegionCupboardShelfTypeId = r.Id
) THEN 1 ELSE 0 END AS IsCounted
FROM FAZIKI.dbo.DF_PMRegionType p
JOIN FAZIKI.dbo.DF_PMRegionCupboardShelfType r ON p.Id = r.RegionTypeId
WHERE p.WarehouseId = 45
) a
ORDER BY a.RegionName;

Sql query to find count with a difference condition and total count in the same query

Here is a sample table I have
Logs
user_id, session_id, search_query, action
1, 100, dog, A
1, 100, dog, B
2, 101, cat, A
3, 102, ball, A
3, 102, ball, B
3, 102, kite, A
4, 103, ball, A
5, 104, cat, A
where
miss = for the same user_id and same session id , if action A is not followed by action B its termed a miss.
Note: action B can happen only after action A has happened.
I am able to find the count of misses for each unique search_query across all users and sessions.
SELECT l1.search_query, count(l1.*) as misses
FROM logs l1
WHERE NOT EXISTS
(SELECT NULL FROM logs l2
WHERE l1.user_id = l2.user_id
AND l1.session_id = l2.session_id
AND l1.session_id != ''
AND l2.action = 'B'
AND l1.action = 'A')
AND l1.action='A'
AND l1.search_query != ''
GROUP BY v1.search_query
order by misses desc;
I am trying to find the value of miss_percentage=(number of misses/total number of rows)*100 for each unique search_query. I couldn't figure out how to find the count with a condition and count without that condition in the same query. Any help would be great.
expected output:
cat 100
kite 100
ball 50
One way to do it is to move the EXISTS into the count
SELECT l1.search_query, count(case when NOT EXISTS
(SELECT 1 FROM logs l2
WHERE l1.user_id = l2.user_id
AND l1.session_id = l2.session_id
AND l1.search_query = l2.search_query
AND l2.action = 'B'
AND l1.action = 'A') then 1 else null end
)*100.0/count(*) as misses
FROM logs l1
WHERE l1.action='A'
AND l1.search_query != ''
GROUP BY l1.search_query
order by misses desc;
This produces the desired results, but also zeros if no misses were found. This can be removed with a HAVING clause, or postprocessing.
Note I also added the clause l1.search_query = l2.search_query that was missing, since otherwise it was counting kite as succeeded, since there is a row with B in the same session.
I think you just need to use case statements here. If I have understood your problem correctly .. then the solution would be something like this -
WITH summary
AS (
SELECT user_id
,session_id
,search_query
,count(1) AS total_views
,sum(CASE
WHEN action = 'A'
THEN 1
ELSE 0
END) AS action_a
,sum(CASE
WHEN action = 'B'
THEN 1
ELSE 0
END) AS action_b
FROM logs l
GROUP BY user_id
,session_id
,search_query
)
SELECT search_query
,(sum(action_a - action_b) / sum(action_a)) * 100 AS miss_percentage
FROM summary
GROUP BY search_query;
You can allways create two queries, and combine them into one with a join. Then you can do the calculations in the bridging (or joining) SQL statement.
In MS-SQL compatible SQL this would be:
SELECT ActiontypeA,countedA,isNull(countedB,0) as countedB,
(countedA-isNull(countedB,0))*100/CountedA as missed
FROM (SELECT search_query as actionTypeA, count(*) as countedA
FROM logs WHERE Action='A' GROUP BY actionType
) as TpA
LEFT JOIN
(SELECT search_query as actionTypeB, count(*) as countedB
FROM logs WHERE Action='B' GROUP BY actionType
) as TpB
ON TpA.ActionTypeA = TpB.ActiontypeB
The LEFT JOIN is required to select all activities (search_query) from the 'A' results, and join them to only those from the 'B' results where a B is available.
Since this is very basic SQL (and well optimized by SQL engines) I'd suggest to prevent WHERE EXISTS as much as possible. The IsNull() function is an MS-SQL function to force a NULL value into the int(0) value which can be used in a calculation.
Finally you could filter on
WHERE missed>0
to get the final result.

SQL Calculate Percentage on 2 columns

I have a problem, I need to calculate the percentage between 2 different columns. Unfortunately I can't get it to work and when I run this all I get is "Invalid column name 'CountOfPlannedVisits'" & "Invalid column name 'CountOfPlannedVisitsClosed'"
SELECT Count(*) As CountOfPlannedVisits, MAX(datename(month, dbo.tblVisit.DateConfirmed)) AS MonthName,
SUM(CASE WHEN tblVisit.VisitTypeRef <> '5' THEN 1 ELSE 0 END) AS CountOfPlannedVisitsClosed, CAST(100.0 * SUM("CountOfPlannedVisits") / SUM(CountOfPlannedVisitsClosed) AS Decimal(5,2) ) As OverallAttendance
FROM dbo.tblContract INNER JOIN
dbo.tblCustomer ON dbo.tblContract.CustomerRef = dbo.tblCustomer.CustomerID INNER JOIN
dbo.tblContractSite ON dbo.tblContract.ContractID = dbo.tblContractSite.ContractRef INNER JOIN
dbo.tblVisit ON dbo.tblContractSite.CardNumber = dbo.tblVisit.CardNumber
WHERE (tblCustomer.CustomerNumber = '08434')
AND (tblVisit.Routine = '1')
AND year(tblVisit.DateConfirmed) = Year('2013')--#DateYear)
AND dbo.IsOnHoldEx(tblContract.OnHold, tblContractSite.OnHold, tblContract.OnHoldStartDate, tblContract.OnHoldEndDate, tblContractSite.OnHoldStartDate, tblContractSite.OnHoldEndDate) = 0
AND tblVisit.Deleted = 0 -- make sure we dont pull through deleted visits
AND (tblContractSite.DateInactive is NULL or tblContractSite.DateInactive > GetDate())
GROUP BY month(dbo.tblVisit.DateConfirmed)
Any help would be greatly appreciated as I'm not really sure where to go from here!
Thanks
You can only reference a column alias (like CountOfPlannedVisits in your case) in the order by clause. Anywhere else you have to repeat the expression or use a subquery table, something like :
select CountOfPlannedVisits,
CountOfPlannedVisitsClosed,
100 * CountOfPlannedVisits / CountOfPlannedVisitsClosed, ...
from (
select some_expression as CountOfPlannedVisits ,
some_other_expression as CountOfPlannedVisitsClosed
....
) a_table
....

SQL Nested Select statements with COUNT()

I'll try to describe as best I can, but it's hard for me to wrap my whole head around this problem let alone describe it....
I am trying to select multiple results in one query to display the current status of a database. I have the first column as one type of record, and the second column as a sub-category of the first column. The subcategory is then linked to more records underneath that, distinguished by status, forming several more columns. I need to display every main-category/subcategory combination, and then the count of how many of each sub-status there are beneath that subcategory in the subsequent columns. I've got it so that I can display the unique combinations, but I'm not sure how to nest the select statements so that I can select the count of a completely different table from the main query. My problem lies in that to display the main category and sub category, I can pull from one table, but I need to count from a different table. Any ideas on the matter would be greatly appreciated
Here's what I have. The count statements would be replaced with the count of each status:
SELECT wave_num "WAVE NUMBER",
int_tasktype "INT / TaskType",
COUNT (1) total,
COUNT (1) "LOCKED/DISABLED",
COUNT (1) released,
COUNT (1) "PARTIALLY ASSEMBLED",
COUNT (1) assembled
FROM (SELECT DISTINCT
(t.invn_need_type || ' / ' || s.code_desc) int_tasktype,
t.task_genrtn_ref_nbr wave_num
FROM sys_code s, task_hdr t
WHERE t.task_genrtn_ref_nbr IN
(SELECT ship_wave_nbr
FROM ship_wave_parm
WHERE TRUNC (create_date_time) LIKE SYSDATE - 7)
AND s.code_type = '590'
AND s.rec_type = 'S'
AND s.code_id = t.task_type),
ship_wave_parm swp
GROUP BY wave_num, int_tasktype
ORDER BY wave_num
Image here: http://i.imgur.com/JX334.png
Guessing a bit,both regarding your problem and Oracle (which I've - unfortunately - never used), hopefully it will give you some ideas. Sorry for completely messing up the way you write SQL, SELECT ... FROM (SELECT ... WHERE ... IN (SELECT ...)) simply confuses me, so I have to restructure:
with tmp(int_tasktype, wave_num) as
(select distinct (t.invn_need_type || ' / ' || s.code_desc), t.task_genrtn_ref_nbr
from sys_code s
join task_hdr t
on s.code_id = t.task_type
where s.code_type = '590'
and s.rec_type = 'S'
and exists(select 1 from ship_wave_parm p
where t.task_genrtn_ref_nbr = p.ship_wave_nbr
and trunc(p.create_date_time) = sysdate - 7))
select t.wave_num "WAVE NUMBER", t.int_tasktype "INT / TaskType",
count(*) TOTAL,
sum(case when sst.sub_status = 'LOCKED' then 1 end) "LOCKED/DISABLED",
sum(case when sst.sub_status = 'RELEASED' then 1 end) RELEASED,
sum(case when sst.sub_status = 'PARTIAL' then 1 end) "PARTIALLY ASSEMBLED",
sum(case when sst.sub_status = 'ASSEMBLED' then 1 end) ASSEMBLED
from tmp t
join sub_status_table sst
on t.wave_num = sst.wave_num
group by t.wave_num, t.int_tasktype
order by t.wave_num
As you notice, I don't know anything about the table with the substatuses.
You can use inner join, grouping and count to get your result:
suppose tables are as follow :
cat (1)--->(n) subcat (1)----->(n) subcat_detail.
so the query would be :
select cat.title cat_title ,subcat.title subcat_title ,count(*) as cnt from
cat inner join sub_cat on cat.id=subcat.cat_id
inner join subcat_detail on subcat.ID=am.subcat_detail_id
group by cat.title,subcat.title
Generally when you need different counts, you need to use the CASE statment.
select count(*) as total
, case when field1 = "test' then 1 else 0 end as testcount
, case when field2 = 'yes' then 1 else 0 endas field2count
FROM table1