SQL combine count and sum in distinct query - count
I have some issues creating a query which should show various statistics for departments - number of cases (new, active, closed, aborted), targets projected and actual (number and value), number of unbalanced cases and amounts.
Part of the code which gives a good picture of what I need is below. "u" table is a CTE where I dumped joins from four tables (Cases , users, notes and payments).
Some of them are sum, subtraction, multiplication or their combination.
(1) Is there a way to not to repeat same count just so I can do subtraction in next column?
Performance is not an issue - statistic is needed daily, so I can queue it to run at midnight, but code bloats quickly with repetitions and I'm not at all sure it is truly distinct, but I have to have some sort of final version of the query before I can start comparing it against raw data.
Also, at this point I'm stumped:
DECLARE #StartExDate datetime
DECLARE #EndExDate datetime
declare #ThisWeekNow int = 0
SET #StartExDate =
(SELECT(CONVERT(DATETIME, (SELECT DATEADD(DAY, 1, EOMONTH(GETDATE(),-1))))))
SET #EndExDate =
(SELECT(CONVERT(DATETIME, (SELECT DATEADD(DAY, 1, EOMONTH(GETDATE()))))))
SET #ThisWeekNow = (SELECT DATEPART(wk, GETDATE()));
WITH u
as
(SELECT tt.team, tt.target, m.client, m.case, m.Created, m.AC_Manager, m.Casetype,
m.Supervisor, m.CAc_Balance, m.OAc_Balance, m.DAc_Balance,m.Notes, m.termsSent,
m.TermsRec, m.Complete, n.Note, clt.Costs, clt.VAT, clt.Type, us.UserCode, us.Manager
from users us
inner join tt
on tt.team = us.Manager
inner join m
on us.Usercode = m.Ac_Manager
inner join n
ON m.client = n.client and m.Case = n.case
inner join clt
on m.Client = clt.Client_Code and m.case = clt.case_No
where m.Created > '2014-03-01 00:00:000'
)
Select distinct
tt.Team
,tt.Target
,(Select count(*) from users us where Us.Manager = tt.team) as 'Team Target'
,(Select count(distinct u.Client+cast(u.case as varchar))
from u where tt.team = u.Manager and
Complete = 0 and u.Created > #StartExDate and u.Created < #EndExDate
) as 'New'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0) as ' All Live'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0
and u.TC_Received is not null) as 'Unsigned'
,(Select a - n from
(Select
(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0) as a
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0
and u.TC_Received is not null) as n
) x ) as 'Worked'
,(Select tt.target - (Select a - n from
(Select
(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0) as a
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0
and u.TC_Rec is not null) as n
) x ) p ) as 'Free capacity'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u
where tt.team = u.Manager and Complete = 0
and patindex('%Signed%',u.note) > 0 ) as 'Signed'
,(Select (SUM(u.costs)+SUM(u.VAT))
from u
where tt.team = u.Manager and u.Complete = 0
and patindex('%Signed%',u.note) > 0 and u.TC_Received is not null
) as 'Actual Income'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 0
and patindex('%Aborted%',u.note) > 0 ) as 'Aborts'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 1 ) as 'Completions'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 1 and u.OAc_Balance > 0
) as 'Office Balances'
,(Select sum (distinct u.OAc_Balance)
from u where tt.team = u.Manager and Complete = 1 ) as 'OB Amount'
,(Select count(distinct u.Client+cast(u.Case as varchar))
from u where tt.team = u.Manager and Complete = 1 and u.CAc_Balance > 0
) as 'Client Balances'
,(Select sum (distinct u.CAc_Balance)
from u where tt.team = u.Manager and Complete = 1) as 'CB Amount'
from tt
join u
on tt.Team = u.Manager
group by tt.Team, tt.Target, u.Usercode
order by tt.Team
This whole procedure is supposed to give us a summary of work being done in company and additional statistics. And looking like that:
Team|Target|Team Members|New| All Live|Unsigned|Worked|Free Capacity|Signed|Actual Income|Aborts|Completions|Office Balances|OB Amount|Client Balances|CB Amount|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
AAA | 360| 8| 2| 247| 223| 24| 336| 71| 85434.6| 4| 165| 22| 1340.84| 87|205777.58|
BBB | 420| 9| 3| 536| 437| 99| 321| 162| 185089.42| 4| 698| 74| 7293.2| 310|942835.87|
CCC | 420| 7| 0| 439| 355| 84| 336| 116| 178517.4| 6| 498| 64| 8604.2| 264|109842.76|
DDD | 420| 9| 0| 725| 290| 435| -15| 189| 61415.2| 7| 591| 64| 7580.54| 256|569165.07|
EEE | 420| 6| 1| 423| 302| 121| 299| 100| 105229.38| 2| 606| 42| 7679.66| 382|126168.31|
FFF | 420| 8| 1| 498| 450| 48| 372| 123| 124665.68| 3| 367| 36| 3947.7| 257| 93294.52|
GGG | 420| 8| 2| 467| 406| 61| 359| 105| 119822.4| 97| 356| 43| 2143.68| 140|215389.32|
HHH | 1| 1| 0| 186| 150| 36| -35| 65| 82878| 0| 81| 22| 2255.2| 84| 6863.74|
III | 360| 7| 1| 527| 454| 73| 287| 158| 165513.58| 6| 417| 42| 3242.08| 160|102729.61|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Total:
Columns 3 through 6 are counts, column seven is Subtraction (Targets-Unsigned), Free capacity is subtraction again: Target-Worked, Actual Income is sum of values for each case (and should be counting same rows as in column Signed) etc. I also need to insert percents columns as well, but this is the question number 1: how to reuse the data (that is: counted in previous column used as argument in arithmetic operation in current)?
Quick count in excel shows every row of column with value is way to big. And the query exec time is already around 100 seconds. Not an issue yet, but would like to lower it.
So question (2): Is there a way to sum same rows as ones counted in previous column with distinct string
Most of the convolutions in procedure would be unnecessary had SQL could parse 'WHERE ( x or y) and ( x1 or x2 or x3)' in anything resembling logic.
I don't know if its a good idea to post sample of U, as it is join of four tables... So - big - sample would have to have several hundred rows at least. Sanitizing that data is a pain.
Related
SQLite Group by last seven days (not weekly!)
I was looking some GROUP BY questions here but no one is like mine. I have a current table like this: |day | client| ---------------- |2020-01-07|id11| |2020-01-07|id10| |2020-01-06|id09| |2020-01-06|id08| |2020-01-05|id07| |2020-01-04|id06| |2020-01-03|id05| |2020-01-03|id04| |2020-01-02|id03| |2020-01-01|id02| |2020-01-01|id01| And I want to create a new column with the ocurrences of unique clients for the last seven days (day - 6) (not weekly!) and show it by day: |day |last 7 day clients| ---------------- |2020-01-07|11| |2020-01-06| 9| |2020-01-05| 7| |2020-01-04| 6| |2020-01-03| 5| |2020-01-02| 3| |2020-01-01| 2| All the aswers here are grouping weekly! What I tryed: pd.read_sql_query("""SELECT DATE(day) dateColumn, COUNT(DISTINCT client) AS seven_day_users FROM table GROUP BY date(dateColumn, '-6 days') ORDER BY dateColumn DESC; """, conn) But the result is grouping by day, not into the interval.
Use a self join of the table and aggregation: SELECT t1.day, COUNT(DISTINCT t2.client) `last 7 day clients` FROM tablename t1 INNER JOIN tablename t2 ON t2.day BETWEEN date(t1.day, '-6 day') AND t1.day GROUP BY t1.day ORDER BY t1.day DESC; See the demo.
sqlite3 recursive aggregation of data
This may be a kind of the Knapsack problem. I need to traverse a data table, group it by a column, choosing ones with better time. Then repeat the previous step until a limit given by column CAPACITY is not reached. This is the demo scenario: create table if not exists data( vid num, size num, epid num, sid num, capacity num, dt ); delete from data; insert into data(vid,size,epid,sid,capacity,dt) values (0,20,1,1,50,1100), -- 2nd choice (0,20,1,1,50,1000), -- 1st choice (0,20,1,1,50,1200), -- last choice excluded because out of capacity (1,20,2,2,50,1100), -- 2nd choice (1,20,2,2,50,1000), -- 1st choice (1,20,2,2,50,1200); -- last choice excluded because out of capacity This is the non recursive solution: with best0 as ( select a.rowid as tid,a.vid,a.sid,a.size,a.dt,a.capacity-a.size as remains,0 as level from data a group by a.sid having min(a.dt) ), best1 as ( select a.tid,a.vid,a.sid,a.size,a.dt,a.remains, a.level from ( select a.rowid as tid,a.sid,a.vid,a.size,a.capacity,a.dt,b.remains-a.size as remains, b.level+1 as level from data a join best0 b on b.sid=a.sid -- and b.level=a.level-1 where not a.rowid in (select tid from best0) and b.remains-a.size>0 ) a group by a.sid having min(a.dt) ), best2 as ( select a.tid,a.vid,a.sid,a.size,a.dt,a.remains, a.level from ( select a.rowid as tid,a.sid,a.vid,a.size,a.capacity,a.dt,b.remains-a.size as remains, b.level+1 as level from data a join best1 b on b.sid=a.sid -- and b.level=a.level-1 where not a.rowid in (select tid from best0 union all select tid from best1) and b.remains-a.size>0 ) a group by a.sid having min(a.dt) ) select * from best0 union all select * from best1 union all select * from best2 And this the result: tid | vid | sid | size | Dtime | capacity | group_level --- | --- | --- | ---- | ----- | -------- | ----------- 2 | 0 | 1 | 20 | 1000 | 30 | 0 5 | 1 | 2 | 20 | 1000 | 30 | 0 1 | 0 | 1 | 20 | 1100 | 10 | 1 4 | 1 | 2 | 20 | 1100 | 10 | 1 This is the recursive version that give error: "recursive reference in a subquery: best" with recursive best(tid,vid,sid,size,dt,remains,level) as ( select a.rowid as tid,a.vid,a.sid,a.size,a.dt,a.capacity-a.size as remains,0 as level from data a group by a.sid having min(a.dt) union all select a.tid,a.vid,a.sid,a.size,a.dt,a.remains, a.level from ( select a.rowid as tid,a.sid,a.vid,a.size,a.dt,b.remains-a.size as remains, b.level+1 as level from data a join best b on b.sid=a.sid -- and b.level=a.level-1 where not a.rowid in (select tid from best) and b.remains-a.size>0 ) a group by a.sid having min(a.dt) ) select * from best I tried differents solutions even using a loop counter but everyone give the same error.
SQLite help for joining and count
I have 2 tables: tblTransactions: transID | type | userID tblusers: userID | name ; Now I want my results to be like: name |count( transactionType1(where type=1)) | transactionType1(where type=2) mr.1 | 2 | 4 mr.2 | 3 | 5 Thanks for your help
Group by the user and then you can use aggregate functions like sum to count the type (with a condition) select u.name, sum(type = 1) as type1_count, sum(type = 2) as type2_count from tblusers u left join tblTransactions t on u.userid = t.userid group by u.name
Suggestion needed writing a complex query - sqlite
I have 4 columns in a table called musics - 'artist','genre', 'writer' , 'producer'. I need to write a query such that, it returns a value 0 , if there are no repetition of values corresponding to the column name; if there is a repetition of values, it should return a value 1, corresponding to that column name. Any help is much appreciated
SELECT (COUNT(artist) <> COUNT(DISTINCT artist)) artist, (COUNT(genre) <> COUNT(DISTINCT genre)) genre, (COUNT(writer) <> COUNT(DISTINCT writer)) writer, (COUNT(producer) <> COUNT(DISTINCT producer)) producer FROM musics Another version SELECT ( SELECT (COUNT(*) > 0) FROM (SELECT 1 FROM musics GROUP BY artist HAVING COUNT(*) > 1) a ) artist, ( SELECT (COUNT(*) > 0) FROM (SELECT 1 FROM musics GROUP BY genre HAVING COUNT(*) > 1) g ) genre, ( SELECT (COUNT(*) > 0) FROM (SELECT 1 FROM musics GROUP BY writer HAVING COUNT(*) > 1) w ) writer, ( SELECT (COUNT(*) > 0) FROM (SELECT 1 FROM musics GROUP BY producer HAVING COUNT(*) > 1) p ) producer Sample data | artist | genre | writer | producer | ------------------------------------------ | artist1 | genre1 | writer1 | producer1 | | artist2 | genre2 | writer1 | producer2 | | artist1 | genre3 | writer3 | producer3 | Sample output: | artist | genre | writer | producer | -------------------------------------- | 1 | 0 | 1 | 0 | SQLFiddle
For Artist select convert(bit,(count(1)-1)) from table_name group by artist -- <-- Replace artist with column name for which duplicate
write a select count statement using distinct with specified column and another select count without distinct and compare both of them based on your requirement
you can use 4 different query with union & each query must contain count(column name) + group by clause
SQLite Select data from multiple rows returned as one row
I would like to know whether it is possible to use a SELECT statement in SQLite to merge the data from two rows into one, similar to how is suggested in the SQL Server forum below. Consider the scenario below which is based on SQL Server (taken from http://forums.aspfree.com/microsoft-sql-server-14/merge-the-two-rows-in-one-row-245550.html) Given there is a table Emp ID | Name | 1 | x | 1 | P | 2 | y | 2 | Q | 3 | W | We want the resulting data from the select statement to output: Emp_Data Id | Name-1 | Name-2 | 1 | x | P | 2 | y | Q | 3 | w | | The answer in the post suggests the following SQL as a possible solution: SELECT a.ID, [Name-1] = ISNULL(( SELECT TOP 1 Name FROM emp WHERE ID = a.ID),''), [Name-2] = ISNULL(( SELECT TOP 1 b.Name FROM emp b WHERE b.ID = a.ID AND Name NOT IN( SELECT TOP 1 Name FROM emp WHERE ID = b.ID )),'') FROM emp a GROUP BY a.ID Using SQLite is it possible to generate the columns [Name-1] & [Name-2] using nested SELECT statements like we can do above in SQL Server?
SELECT a.ID, COALESCE(a.Name,'') as "Name-1", COALESCE((SELECT b.Name FROM Emp b WHERE b.ID = a.ID AND b.rowid != a.rowid LIMIT 1),'') as "Name-2" FROM emp a GROUP BY a.ID
Doug's solution didn't work for me. The code below, however, did work for me but it's very slow... SELECT a.ID, a.Name AS Name1, (SELECT b.Name FROM Emp b WHERE b.ID = a.ID AND b.Name != a.Name LIMIT 1) AS Name2 FROM emp a GROUP BY a.ID
try this::: select id, group_concat(name) from emp group by id; ;)