SQL calculation based on another column - sql

I am extracting data out of SQL database and need to calculate the opening balance of a stock item per project. I am getting the opening balance for the stock inclusive of all the projects.
item code | Project | Qty In | Qty Out
----------+---------+--------+---------
1234 1 0 90
1234 1 90 0
1234 2 431 0
1234 2 0 22
1234 3 925 0
1234 3 0 925
1234 3 925 0
1234 3 0 20
1234 3 0 40
1234 3 0 30
1234 3 0 40
1234 3 0 60
1234 3 0 50
1234 3 0 24
1234 3 0 40
1234 3 0 30
1234 3 0 17
1234 3 0 80
1234 3 0 30
1234 4 16 0
1234 4 0 16
1234 5 22 0
1234 5 0 23
Query:
select OpeningBalanceQty = Qty_On_Hand +
(select case when ServiceItem = 0
then IsNull(sum (QtyOut), 0)
else 0
end
from table1
where AccountLink=StockLink and txdate>='2016-06-01' and project ='2' ) -
(select case when ServiceItem = 0
then IsNull(sum (QtyIn), 0)
else 0
end from table1
where AccountLink=StockLink and txdate>='2016-06-01' and project ='2')
from tablel join table2 on table1.AccountLink = table2.StockLink
I have used project 2 as an example, it has two transactions(qty in:431)& (qty out:22)
My opening balance should be 409 but it is giving the total for the product item
My full code:
select Table1.TxDate,Table2.Pack,Table1.Reference,
OpeningBalanceQty= (select case when ServiceItem = 0 then IsNull(sum
(QtyOut), 0) else 0 end from Table1 where AccountLink=StockLink and
ProjectCode in('2') ) - (select case when ServiceItem = 0 then IsNull(sum
(QtyIn), 0) else 0 end from Table1 where AccountLink=StockLink and
ProjectCode in('2'))
,ProjectCode,ProjectDescription, Code, Description_1, Sum(ActualQuantity)*-1
as [Qty Processed],Sum(Debit)-Sum(Credit) as [Value],Trcode
from Table1
join Table2
on Table1 .AccountLink = Table2.StockLink
where ServiceItem = 0 and txdate>='2017-06-01 00:00:00' and txdate<='2017-
06-30 00:00:00' and Code='1234'
Group by Description_1, Code,ProjectCode, ProjectDescription, stocklink,
serviceitem,Qty_On_Hand,Table1.Reference,Table2.Pack,Table1.TxDate,trcode

Do you think this could be helpful for you?
SELECT PROJECT, SUM( QTYIN-QTYOUT) AS OPEN_BAL_QTY
FROM yourtable
WHERE txdate>='2016-06-01'
GROUP BY PROJECT
Output:
PROJECT OPEN_BAL_QTY
1 0
2 409
3 464
4 0
5 -1
1° update: after your new information (pls, next time, try to give all the information in your initial post, and well formatted: see tour of stackoverflow to learn how to do).
If you are using MSSQL 2005 or later, you can try this:
SELECT TABLE1.TXDATE
,TABLE2.PACK
,TABLE1.REFERENCE
, SUM(QTYIN-QTYOUT) OVER (PARTITION BY TABLE1.PROJECTCODE) AS OPEN_BAL_QTY
,PROJECTCODE
,PROJECTDESCRIPTION
,CODE
,DESCRIPTION_1
,-SUM(ACTUALQUANTITY) AS QTY PROCESSED
, SUM(DEBIT) - SUM(CREDIT) AS VALUE
,TRCODE
FROM TABLE1
JOIN TABLE2 ON TABLE1.ACCOUNTLINK = TABLE2.STOCKLINK
WHERE SERVICEITEM = 0
AND TXDATE >= '2017-06-01 00:00:00'
AND TXDATE <= '2017-06-30 00:00:00'
AND CODE = '1234'
GROUP BY DESCRIPTION_1
,CODE
,PROJECTCODE
,PROJECTDESCRIPTION
,STOCKLINK
,SERVICEITEM
,QTY_ON_HAND
,TABLE1.REFERENCE
,TABLE2.PACK
,TABLE1.TXDATE
,TRCODE
2° update
If it doesn't work for you, you should try:
SELECT A.*
,B.OPEN_BAL_QTY
FROM
SELECT TABLE1.TXDATE
,TABLE2.PACK
,TABLE1.REFERENCE
,PROJECTCODE
,PROJECTDESCRIPTION
,CODE
,DESCRIPTION_1
,-SUM(ACTUALQUANTITY) AS QTY PROCESSED
, SUM(DEBIT) - SUM(CREDIT) AS VALUE
,TRCODE
FROM TABLE1
JOIN TABLE2 ON TABLE1.ACCOUNTLINK = TABLE2.STOCKLINK
WHERE SERVICEITEM = 0
AND TXDATE >= '2017-06-01 00:00:00'
AND TXDATE <= '2017-06-30 00:00:00'
AND CODE = '1234'
GROUP BY DESCRIPTION_1
,CODE
,PROJECTCODE
,PROJECTDESCRIPTION
,STOCKLINK
,SERVICEITEM
,QTY_ON_HAND
,TABLE1.REFERENCE
,TABLE2.PACK
,TABLE1.TXDATE
,TRCODE
) A
LEFT JOIN (SELECT PROJECTCODE, SUM( QTYIN-QTYOUT) AS OPEN_BAL_QTY
FROM TABLE1
WHERE TXDATE>='2017-06-01'
AND TXDATE <= '2017-06-30 00:00:00'
GROUP BY PROJECT) B ON A.PROJECT_CODE = B.PROJECT_CODE

Related

Count average with multiple conditions

I'm trying to create a query which allows to categorize the average percentage for specific data per month.
Here's how my dataset presents itself:
Date
Name
Group
Percent
2022-01-21
name1
gr1
5.2
2022-01-22
name1
gr1
6.1
2022-01-26
name1
gr1
4.9
2022-02-01
name1
gr1
3.2
2022-02-03
name1
gr1
8.1
2022-01-22
name2
gr1
36.1
2022-01-25
name2
gr1
32.1
2022-02-10
name2
gr1
35.8
...
...
...
...
And here's what I want to obtain with my query (based on what I showed of the table):
Month
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
01
1
1
0
0
02
1
1
0
0
...
...
...
...
...
The result needs to:
Be ordered by month
Have the average use for each name counted and categorized
So far I know how to get the average of the Percent value per Name:
SELECT Name,
AVG(Percent)
from `table`
where Group = 'gr1'
group by Name
and how to count iterations of Percent in the categories created for the query:
SELECT EXTRACT(MONTH FROM Date) as Month,
COUNT(CASE WHEN Percent <= 25 AND Group = 'gr1' THEN Name END) `_25`,
COUNT(CASE WHEN Percent > 25 AND Percent <= 50 AND Group = 'gr1' THEN Name END) `_50`,
COUNT(CASE WHEN Percent > 50 AND Percent <= 75 AND Group = 'gr1' THEN Name END) `_75`,
COUNT(CASE WHEN Percent > 75 AND Percent <= 100 AND Group = 'gr1' THEN Name END) `_100`,
FROM `table`
GROUP BY Month
ORDER BY Month
but this counts all iterations of every name where I want the average of those values.
I've been struggling to figure out how to combine the two queries or to create a new one that answers my need.
I'm working with the BigQuery service from Google Cloud
This query produces the needed result, based on your example. So basically this combines your 2 queries using subquery, where the subquery is responsible to calculate AVG grouped by Name, Month and Group, and the outer query is for COUNT and "categorization"
SELECT
Month,
COUNT(CASE
WHEN avg <= 25 THEN Name
END) AS _25,
COUNT(CASE
WHEN avg > 25
AND avg <= 50 THEN Name
END) AS _50,
COUNT(CASE
WHEN avg > 50
AND avg <= 75 THEN Name
END) AS _75,
COUNT(CASE
WHEN avg > 75
AND avg <= 100 THEN Name
END) AS _100
FROM
(
SELECT
EXTRACT(MONTH from Date) AS Month,
Name,
AVG(Percent) AS avg
FROM
table1
GROUP BY Month, Name, Group
HAVING Group = 'gr1'
) AS namegr
GROUP BY Month
This is the result:
Month
_25
_50
_75
_100
1
1
1
0
0
2
1
1
0
0
See also Fiddle (BUT on MySql) - http://sqlfiddle.com/#!9/16c5882/9
You can use this query to Group By Month and each Name
SELECT CONCAT(EXTRACT(MONTH FROM Date), ', ', Name) AS DateAndName,
CASE
WHEN AVG(Percent) <= 25 THEN '1'
ELSE '0'
END AS '<=25%',
CASE
WHEN AVG(Percent) > 25 AND AVG(Percent) <= 50 THEN '1'
ELSE '0'
END AS '25<_<=50%',
CASE
WHEN AVG(Percent) > 50 AND AVG(Percent) <= 75 THEN '1'
ELSE '0'
END AS '50<_<=75%',
CASE
WHEN AVG(Percent) > 75 AND AVG(Percent) <= 100 THEN '1'
ELSE '0'
END AS '75<_<=100%'
from DataTable /*change to your table name*/
group by EXTRACT(MONTH FROM Date), Name
order by DateAndName
It gives the following result:
DateAndName
<=25%
25<_<=50%
50<_<=75%
75<_<=100%
1, name1
1
0
0
0
1, name2
0
1
0
0
2, name1
1
0
0
0
2, name2
0
1
0
0

SQL Consecutive Date Cumulative Count

I am doing some roster analysis and need to identify when an employee has worked for 5 or more consecutive days. In my table, I can extract data something like the below (note, there are lot more columns, this is just a cut down example):
Emp
Start
First_Entry
1234
23/06/2016
1
1234
24/06/2016
1
1234
24/06/2016
0
1234
25/06/2016
1
1234
26/06/2016
1
1234
27/06/2016
1
1234
28/06/2016
1
1234
29/06/2016
1
1234
29/06/2016
0
1234
30/06/2016
1
1234
2/07/2016
1
1234
3/07/2016
1
1234
3/07/2016
0
1234
4/07/2016
1
1234
4/07/2016
0
1234
5/07/2016
1
1234
6/07/2016
1
1234
9/07/2016
1
1234
10/07/2016
1
1234
11/07/2016
1
1234
12/07/2016
1
And what I am after is something like this:
Emp
Start
First_Entry
Consecutive_Days
Over_5
Status
1234
23/06/2016
1
1
0
Worked < 5
1234
24/06/2016
1
2
0
Worked < 5
1234
24/06/2016
0
2
0
Worked < 5
1234
25/06/2016
1
3
0
Worked < 5
1234
26/06/2016
1
4
0
Worked < 5
1234
27/06/2016
1
5
1
Worked >= 5
1234
28/06/2016
1
6
1
Worked >= 5
1234
29/06/2016
1
7
1
Worked >= 5
1234
29/06/2016
0
7
1
Worked >= 5
1234
30/06/2016
1
8
1
Worked >= 5
1234
02/07/2016
1
1
0
Worked < 5
1234
03/07/2016
1
2
0
Worked < 5
1234
03/07/2016
0
2
0
Worked < 5
1234
04/07/2016
1
3
0
Worked < 5
1234
04/07/2016
0
3
0
Worked < 5
1234
05/07/2016
1
4
0
Worked < 5
1234
06/07/2016
1
5
1
Worked >= 5
1234
09/07/2016
1
1
0
Worked < 5
1234
10/07/2016
1
2
0
Worked < 5
1234
11/07/2016
1
3
0
Worked < 5
1234
12/07/2016
1
4
0
Worked < 5
I'm really not sure how to go about getting the cumulative count for consecutive days, so any help you can give will be amazing
Probably someone would come up with a brilliant solution but this would do. Your problem looks like an "Gaps and Islands" problem. Finding islands of date ranges we can find out the rest easily. In the below SQL, #mindate is not a must, but makes it easier.
CREATE TABLE #temptable
(
[Emp] CHAR(4),
[startDate] DATE,
[First_Entry] BIT
);
INSERT INTO #temptable
(
[Emp],
[startDate],
[First_Entry]
)
VALUES
('1234', N'2016-06-23', 1),
('1234', N'2016-06-24', 1),
('1234', N'2016-06-24', 0),
('1234', N'2016-06-25', 1),
('1234', N'2016-06-26', 1),
('1234', N'2016-06-27', 1),
('1234', N'2016-06-28', 1),
('1234', N'2016-06-29', 1),
('1234', N'2016-06-29', 0),
('1234', N'2016-06-30', 1),
('1234', N'2016-07-02', 1),
('1234', N'2016-07-03', 1),
('1234', N'2016-07-03', 0),
('1234', N'2016-07-04', 1),
('1234', N'2016-07-04', 0),
('1234', N'2016-07-05', 1),
('1234', N'2016-07-06', 1),
('1234', N'2016-07-09', 1),
('1234', N'2016-07-10', 1),
('1234', N'2016-07-11', 1),
('1234', N'2016-07-12', 1);
DECLARE #minDate DATE;
SELECT #minDate = DATEADD(d, -1, MIN(startDate))
FROM #temptable;
WITH firstOnly
AS (SELECT *
FROM #temptable
WHERE First_Entry = 1),
grouper (emp, startDate, grp)
AS (SELECT Emp,
startDate,
DATEDIFF(d, #minDate, startDate) - ROW_NUMBER() OVER (PARTITION BY Emp ORDER BY startDate)
FROM firstOnly),
islands (emp, START, [end])
AS (SELECT emp,
MIN(startDate),
MAX(startDate)
FROM grouper
GROUP BY emp,
grp),
consecutives (emp, startDate, consecutive_days)
AS (SELECT f.Emp,
f.startDate,
-- i.START,
-- i.[end],
ROW_NUMBER() OVER (PARTITION BY f.Emp, i.START ORDER BY i.START)
FROM firstOnly f
INNER JOIN islands i
ON f.startDate
BETWEEN i.START AND i.[end])
SELECT t.Emp,
t.startDate,
t.First_Entry,
c.consecutive_days,
CAST(CASE
WHEN c.consecutive_days < 5 THEN
0
ELSE
1
END AS BIT) Over_5,
CASE
WHEN c.consecutive_days < 5 THEN
'Worked < 5'
ELSE
'Worked >= 5'
END [Status]
FROM consecutives c
INNER JOIN #temptable t
ON t.Emp = c.emp
AND t.startDate = c.startDate;
DROP TABLE #temptable;
This is a island and gap problem, You can try to use LAG window function to get the previous startDate row for each Emp, ten use SUM window function to calculate which days are continuous.
Finally, We can use CASE WHEN expression to judge whether the day is greater than 5.
;WITH CTE AS (
SELECT [Emp],
[startDate],
[First_Entry],
SUM(CASE WHEN DATEDIFF(dd,f_Dt,startDate) <= 1 THEN 0 ELSE 1 END) OVER(PARTITION BY Emp ORDER BY startDate) grp
FROM (
SELECT *,
LAG(startDate,1,startDate) OVER(PARTITION BY Emp ORDER BY startDate) f_Dt
FROM T
) t1
)
SELECT [Emp],
[startDate],
[First_Entry],
SUM(CASE WHEN First_Entry = 1 THEN 1 ELSE 0 END) OVER(PARTITION BY Emp,grp ORDER BY startDate) Consecutive_Days,
(CASE WHEN SUM(CASE WHEN First_Entry = 1 THEN 1 ELSE 0 END) OVER(PARTITION BY Emp,grp ORDER BY startDate) >= 5 THEN 1 ELSE 0 END) Over_5,
(CASE WHEN SUM(CASE WHEN First_Entry = 1 THEN 1 ELSE 0 END) OVER(PARTITION BY Emp,grp ORDER BY startDate) >= 5 THEN 'Worked >= 5' ELSE 'Worked < 5' END) Status
FROM CTE
sqlfiddle

PIVOT table in oracle sql

I have data like this :
end date billing
30-NOV-16 0
31-DEC-16 0
31-JAN-17 0
28-FEB-17 208200
31-MAR-17 362950
and when I run this query :
SELECT *
FROM
(SELECT
ps.end_date end_date
, ps.itd_gross_billing billing
FROM project_summary_v ps
JOIN projects_dtl pd ON ps.project_id=pd.project_id
JOIN periods_dim xpd ON ps.end_date=xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
)
PIVOT
(
max(billing)
FOR end_date in ( '31-OCT-16'
,'30-NOV-16'
,'31-DEC-16'
,'31-JAN-17'
,'28-FEB-17'
,'31-MAR-17' )
);
I get the following output
31-OCT-16 30-NOV-16 31-DEC-16 31-JAN-17 28-FEB-17 31-MAR-17
0 0 0 0 208200 362950
All good so far. But when I have few more columns data,
end date billing pd_data mn_data
31-OCT-16 0 10 1
30-NOV-16 0 100 2
31-DEC-16 0 200 3
31-JAN-17 0 90 4
28-FEB-17 208200 30 5
31-MAR-17 362950 50 6
How to transpose this table ? Also if the end date is dynamic ( as of now I have hard coded )- What should be the query inside the in ( ) .
Output should be something like this :
31-OCT-16 30-NOV-16 31-DEC-16 31-JAN-17 28-FEB-17 31-MAR-17
billing 0 0 0 0 208200 362950
pd_data 10 100 200 90 30 50
mn_data 1 2 3 4 5 6
I think the below query would work. I have separated the queries to pivot. Hope this helps.
SELECT *
FROM
(SELECT ps.end_date end_date ,
ps.itd_gross_billing billing
FROM project_summary_v ps
JOIN projects_dtl pd
ON ps.project_id=pd.project_id
JOIN periods_dim xpd
ON ps.end_date =xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
) pivot( MAX(billing) FOR end_date IN ( '31-OCT-16' ,'30-NOV-16' ,'31-DEC-16' ,'31-JAN-17' ,'28-FEB-17' ,'31-MAR-17' ) )
UNION ALL
SELECT *
FROM
(SELECT ps.end_date end_date ,
ps.pd_data pd_data
FROM project_summary_v ps
JOIN projects_dtl pd
ON ps.project_id=pd.project_id
JOIN periods_dim xpd
ON ps.end_date =xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
) pivot( MAX(pd_data) FOR end_date IN ( '31-OCT-16' ,'30-NOV-16' ,'31-DEC-16' ,'31-JAN-17' ,'28-FEB-17' ,'31-MAR-17' ) )
UNION ALL
SELECT *
FROM
(SELECT ps.end_date end_date ,
ps.mn_data mn_data
FROM project_summary_v ps
JOIN projects_dtl pd
ON ps.project_id=pd.project_id
JOIN periods_dim xpd
ON ps.end_date =xpd.end_date
WHERE pd.project_number=100
FETCH FIRST 6 rows only
) pivot( MAX(mn_data) FOR end_date IN ( '31-OCT-16' ,'30-NOV-16' ,'31-DEC-16' ,'31-JAN-17' ,'28-FEB-17' ,'31-MAR-17' ) )

aging structure using sql query

I have a table structure like the following
TNO DATE NETAMT CHQ CASH PARTY
---------------------------------------------
T1 01/04/2016 100 10 0 TEST1
T2 15/04/2016 50 0 0 TEST2
T3 18/04/2016 100 100 0 TEST3
Now I want to make a SQL query which will give me an aging report of which transactions are lying outstanding in which slabs.
I want to see the result in the following format
PARTY 0-3 DAYS 4-6 DAYS 7-15 DAYS
---------------------------------------------
TEST1 0 0 90
TEST2 0 50 0
TEST3 0 0 0
Try this
SELECT PARTY,
SUM(CASE WHEN DATEDIFF(DAY,[DATE],GETDATE()) BETWEEN 0 AND 3 THEN (NETAMT - CHQ) ELSE 0 END) AS [0_3_DAYS],
SUM(CASE WHEN DATEDIFF(DAY,[DATE],GETDATE()) BETWEEN 4 AND 6 THEN (NETAMT - CHQ) ELSE 0 END) AS [4_6_DAYS],
SUM(CASE WHEN DATEDIFF(DAY,[DATE],GETDATE()) BETWEEN 7 AND 15 THEN (NETAMT - CHQ) ELSE 0 END) AS [7_15_DAYS],
FROM TABLE1
GROUP BY PARTY

Fetch data in MS SQL 2008

I have three tables which are like:
table1
id,
created_Date
table2
id
district_ID
status_ID
table3
district_ID
district_Name
Now i need the records in following format
Srno District_name <10 days >10 and <20 days >20 days
1 xxx 12 15 20
2 yyy 8 0 2
count days as per current date
for example: if the created date is 10-08-2013 and current date is 13-08-2013 the date difference will be 3
So what should my query be? Any suggestions will be appreciated.
Thank you
table1
id created_Date
1 2013-07-12 13:32:10.957
2 2013-07-12 13:32:10.957
3 2013-08-01 10:00:10.957
4 2013-08-10 13:32:10.957
5 2013-08-10 14:32:10.957
table2
id district_ID status_id
1 1 3
2 2 3
3 2 7
4 3 4
5 4 3
table1
district_ID district_Name
1 xxx
2 yyy
3 zzz
4 aaa
5 bbb
I would have a look at using DATEDIFF and CASE.
DATEDIFF (Transact-SQL)
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.
Something like
SELECT District_name,
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) < 10
THEN 1
ELSE 0
END
) [<10 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 10 AND DATEDIFF(day,created_Date, getdate()) < 20
THEN 1
ELSE 0
END
) [>10 and <20 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 20
THEN 1
ELSE 0
END
) [>20 days]
FROM Your_Tables_Here
GROUP BY District_name
;with cte as (
select t3.district_Name, datediff(day, t1.created_Date, getdate()) as diff
from table1 as t1 as t1
inner join table2 as t2 on t2.id = t1.id
inner join table3 as t3 on t3.district_id = t2.district_id
)
select
district_Name,
sum(case when diff < 10 then 1 else 0 end) as [<10 days],
sum(case when diff >= 10 and diff < 20 then 1 else 0 end) as [>=10 and < 20 days],
sum(case when diff >= 20 then 1 else 0 end) as [>= 20 days]
from cte
group by district_Name