How To Group By Only Some Rows - plsql

I have some records.
ID Salary WillGroupBy Amount
----------------------------------------
6320 100 1 15
6320 150 1 20
6694 200 0 25
6694 300 0 30
7620 400 1 45
7620 500 1 50
How can I group by only which "WillGroupBy = 1" records?
(I will SUM Salary and Amount columns)
I want to get this result:
ID Salary WillGroupBy Amount
----------------------------------------
6320 250 1 35
6694 200 0 25
6694 300 0 30
7620 900 1 95
Can you help me please :( ?
Solution:
SELECT ID, SUM(Salary) Salary, WillGroupBy, SUM(Amount) Amount
FROM YourTable
where WILLGROUPBY = 0
union all
SELECT ID, SUM(Salary) Salary, WillGroupBy, SUM(Amount) Amount
FROM YourTable
where WILLGROUPBY = 1
group by ID, WillGroupBy
I used this solution via Erhan.
I would to know that how it could be in another way.

With MySQL you can do:
SELECT ID, SUM(Salary) Salary, WillGroupBy, SUM(Amount) Amount, #row := #row + 1
FROM YourTable
JOIN (SELECT #row := 0) v
GROUP BY ID, IF(WillGroupBy = 1, -1, #row)
DEMO

Related

R: Create groups within column

I'm trying to group an age column into an age group column and summarize by that grouping.
ie I need the dataset below -
AGE
1
2
5
68
27
4
2
33
45
To become
AGE_GRP COUNT
1-10 5
11-20 0
21-30 1
31-40 1
40+ 2
I'm using R
Thanks.
You need CASE statement to split the AGE into different groups
SELECT CASE
WHEN AGE BETWEEN 1 AND 10 THEN '1-10'
WHEN AGE BETWEEN 11 AND 20 THEN '11-20'
WHEN AGE BETWEEN 21 AND 30 THEN '21-30'
WHEN AGE BETWEEN 31 AND 40 THEN '31-40'
ELSE '40+'
END AS AGE_GRP,
Count(1) as Cnt
FROM yourtable
GROUP BY CASE
WHEN AGE BETWEEN 1 AND 10 THEN '1-10'
WHEN AGE BETWEEN 11 AND 20 THEN '11-20'
WHEN AGE BETWEEN 21 AND 30 THEN '21-30'
WHEN AGE BETWEEN 31 AND 40 THEN '31-40'
ELSE '40+'
END
If you don't want to repeat the CASE statement in GROUP BY then use this
SELECT AGE_GRP,
Count(1) AS cnt
FROM (SELECT CASE
WHEN AGE BETWEEN 1 AND 10 THEN '1-10'
WHEN AGE BETWEEN 1 AND 10 THEN '11-20'
WHEN AGE BETWEEN 1 AND 10 THEN '21-30 '
WHEN AGE BETWEEN 1 AND 10 THEN '31-40'
ELSE '40+'
END AS AGE_GRP
FROM yourtable) A
GROUP BY AGE_GRP
You have zero values so you need a left join:
select agegrp, count(t.agegrp)
from (select '1-10' as agegrp, 1 as lowb, 10 as hib union all
select '11-20' as agegrp, 11, 20 union all
select '21-30' as agegrp, 21, 30 upperbound union all
select '31-40' as agegrp, 31, 40 as upperbound union all
select '40+' as agegrp, 41, NULL as upperbound
) ag left join
t
on t.age >= ag.lowb and t.age <= ag.hib
group by ag.agegrp
order by ag.lowb;
Note: this assumes the column is an integer, so a value like 30.5 isn't allowed. It is easy to adjust the query to handle non-integer ages, if that is the requirement.

SQLite : Need to combine results from one table with another result

I have 2 tables :
payments:
id amount type code
1 1200 0 111
2 100 1 111
3 200 0 111
4 50 0 112
5 500 2 112
6 300 3 113
bills:
id details code
-----------------------
1 bill-1 111
2 bill-2 112
3 bill-3 113
4 bill-4 114
I wanted to sum the amounts in payments table and join it with bills like below
result:
bills.code type0Sum type1Sum type2Sum type3Sum
-------------------------------------------------------------------------
111 1400 100 0 0
112 50 0 500 0
113 0 0 0 300
114 0 0 0 0
Sorry if this is a newbie question
[Edit]
I have used a similar query as below :
SELECT *
FROM bills,
(SELECT SUM(amount) AS type0Sum, code
FROM payments
WHERE type = 0
GROUP BY code)
AS sub1,
(SELECT SUM(amount) AS type1Sum, code
FROM payments
WHERE type = 1
GROUP BY ref_code)
AS sub2
WHERE bills.code = sub1.code
AND bills.code = sub2.code
But I am getting only the rows those having the type like :
bills.code type0Sum type1Sum type2Sum type3Sum
-------------------------------------------------------
111 1400 100
I've modified that final query to do proper joins, not the old joins that you were doing (read up on cartesian joins). Give this one a go for you, see if it works;
SELECT b.code
,sub1.type0Sum
,sub2.type1Sum
FROM bills b
LEFT JOIN (
SELECT SUM(amount) AS type0Sum
,code
FROM payments
WHERE type = 0
GROUP BY code
) AS sub1 ON b.code = sub1.code
LEFT JOIN (
SELECT SUM(amount) AS type1Sum
,code
FROM payments
WHERE type = 1
GROUP BY ref_code
) AS sub2 ON b.code = sub2.code
There are other ways of doing this that are more efficient but I've kept to your query in order to help you learn.

SQLite select inside of update

So there are 2 tables, Transactions with created_at column and Transaction_associations with amount and remaining_balance columns, among others. I need to calculate a running sum(total) on the amount column, sorted by the created_at column, obviously. The only problem is that I need to get the SUM of all transactions that are created before the current transaction that is being calculated. I would've needed a select inside the update query in order to SELECT a current_transactions table in order to get hold of the current created_at date. However I can't. Am I missing something? Are there alternatives to this method?
UPDATE Transaction_associations SET remaining_balance =
(
SELECT SUM (Transaction_associations.amount)
FROM Transactions
JOIN Transaction_associations ON Transactions.id = transaction_id
WHERE created_at <= current_transactions.created_at // here
)
WHERE id IN
(
SELECT id
FROM Transaction_associations
JOIN Transactions ON Transactions.id = transaction_id
WHERE created_at >= '2014-11-24'
)
Edit: Added example.
Transactions Transaction_associations
created_at amount remaining_balance
2014-02-01 100 100
2014-03-01 50 150
2014-04-01 205 355
Later Edit: Added complete code for use on SQLFiddle. I've replaced Transaction_associations with TA2 on SUM, as it complains of misuse of aggregate: SUM()
DROP TABLE IF EXISTS Transactions;
DROP TABLE IF EXISTS Transaction_associations;
CREATE TABLE Transactions ( id integer, created_at text);
CREATE TABLE Transaction_associations ( id integer, amount integer, remaining_balance integer, transaction_id integer);
INSERT INTO Transactions VALUES (1,'2015');
INSERT INTO Transactions VALUES (2,'2014');
INSERT INTO Transactions VALUES (3,'2013');
INSERT INTO Transactions VALUES (4,'2012');
INSERT INTO Transactions VALUES (5,'2010');
INSERT INTO Transaction_associations VALUES (6, 100, 0, 1);
INSERT INTO Transaction_associations VALUES (7, 20, 0, 2);
INSERT INTO Transaction_associations VALUES (8, 3, 0, 3);
INSERT INTO Transaction_associations VALUES (9, 40, 0, 4);
INSERT INTO Transaction_associations VALUES (10, 500, 0, 5);
UPDATE Transaction_associations
SET remaining_balance =
(
SELECT SUM(TA2.amount)
FROM Transactions
JOIN Transaction_associations AS TA2 ON Transactions.id = TA2.transaction_id
WHERE created_at <= (SELECT created_at
FROM Transactions
WHERE id = TA2.transaction_id)
)
WHERE transaction_id IN
(
SELECT id
FROM Transactions
WHERE created_at >= '2013'
);
SELECT * from Transactions join Transaction_associations on Transactions.id = Transaction_associations.transaction_id;
This results in, which is wrong:
1 2015 6 100 663 1
2 2014 7 20 663 2
3 2013 8 3 663 3
4 2012 9 40 0 4
5 2010 10 500 0 5
Result should be:
1 2015 6 100 663 1
2 2014 7 20 563 2
3 2013 8 3 543 3
4 2012 9 40 0 4
5 2010 10 500 0 5
To use the same table name multiple times, rename one of them. This is not possible with UPDATE, so you have to do this in the SELECT.
To look up the corresponding timestamp, use another subquery.
Together with some simplifications, this becomes:
UPDATE Transaction_associations
SET remaining_balance =
(
SELECT SUM(TA2.amount)
FROM Transactions
JOIN Transaction_associations AS TA2 ON Transactions.id = TA2.transaction_id
WHERE created_at <= (SELECT created_at
FROM Transactions
WHERE id = Transaction_associations.transaction_id)
)
WHERE transaction_id IN
(
SELECT id
FROM Transactions
WHERE created_at >= '2014-11-24'
);

SQLITE: Getting difference from two different column values

I have 2 tables naming..InvoiceGarmentService and Payment..
InvoiceGarmentService Table Data
----------------------------------
IGSID InvoiceID Price
0 1001 50
1 1001 100
2 1002 500
3 1002 600
------------------------------------
Payment Data
------------------------------------
PaymentID InvoiceID Amount
0 1001 20
1 1002 300
2 1003 900
------------------------------------
I want to get the due amount ie. (Sum of Price From IGS)-(Sum of Amount from Payment)
I have used a query like this
SELECT sum(Price) FROM InvoiceGarmentService - sum(Amount)FROM Payment
WHERE InvoiceGarmentService.InvoiceID='1001'
But I am Unable to find result..saying here is a syntax error but I dn knw about that..
Anyone can help me
SELECT igs.InvoiceID, (val1 - val2)
FROM (SELECT InvoiceID, sum(Price) AS val1
FROM InvoiceGarmentService
GROUP BY InvoiceID) igs
JOIN (SELECT InvoiceID, sum(Amount) AS val2
FROM Payment
GROUP BY InvoiceID) p
ON (igs.InvoiceID = p.InvoiceID)
WHERE igs.InvoiceID = '1001'

SQL Count Data 1/2 hourly

I have a stored procedure that counts data for each hour,
Declare #DateTimeToFilter DATETIME;
--set #DateTimeToFilter = GetDate();
set #DateTimeToFilter = '6/5/14'
SET NOCOUNT ON;
WITH H ([Hour]) AS
( SELECT 7 UNION
SELECT 8 UNION
SELECT 9 UNION
SELECT 10 UNION
SELECT 11 UNION
SELECT 12 UNION
SELECT 13 UNION
SELECT 14 UNION
SELECT 15 UNION
SELECT 16 UNION
SELECT 17 UNION
SELECT 18 UNION
SELECT 19
)
SELECT H.[Hour],
COUNT(T.BookingID) AS NoOfUsers
FROM H
LEFT JOIN tbl_Visitor T
ON H.[Hour] = DATEPART(HOUR, T.TimeofArrival) AND
((DATEDIFF(dd, T.TimeofArrival, #DateTimeToFilter) = 0) AND (DATEDIFF(mm, T.TimeofArrival, #DateTimeToFilter) = 0) AND
(DATEDIFF(yy, T.TimeofArrival, #DateTimeToFilter) = 0))
GROUP BY H.[Hour];
This forces the data returned for each hour irrespective of whether there is any data or not.
How could I add the half hourly data to be added also, so the returned data look like.
Hour Count
7 0
7.5 0
8 0
8.5 0
9 0
9.5 0
10 4
10.5 0
11 0
11.5 0
12 0
12.5 0
13 0
13.5 0
14 5
14.5 0
15 2
15.5 0
16 2
16.5 0
17 0
17.5 0
18 0
18.5 0
19 0
19.5 0
The data is stored in the database as a smalltimedate, i.e. 2014-06-05 14:00:00
Any help is appreciated.
You can use minutes instead of hours:
with h ([Minute]) as (
select 420 union all
select 450 union all
select 480 union all
select 510 union all
select 540 union all
...
Divide the minutes to get fractional hours:
select h.[Minute] / 60.0 as [Hour], ...
Calculate the start and stop time for the interval to filter the data:
... on T.TimeofArrival >= dateadd(minute, h.[Minute], #DateTimeToFilter) and
T.TimeofArrival < dateadd(minute, h.[Minute] + 30, #DateTimeToFilter)
Below is an example that groups by half-hour intervals and can easily be extended for other intervals. I suggest you avoid applying functions to columns in the WHERE clause as that prevents indexes on those columns from being used efficiently.
DECLARE
#DateTimeToFilter smalldatetime = '2014-06-05'
, #IntervalStartTime time = '07:00:00'
, #IntervalEndTime time = '20:00:00'
, #IntervalMinutes int = 30;
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
, t256 AS (SELECT 0 AS n FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d)
, t64k AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) AS num FROM t256 AS a CROSS JOIN t256 AS b)
, intervals AS (SELECT DATEADD(minute, (num - 1) * #IntervalMinutes, #DateTimeToFilter) AS interval
FROM t64k
WHERE num <= 1440 / #IntervalMinutes)
SELECT
interval
, CAST(DATEDIFF(minute, #DateTimeToFilter, interval) / 60.0 AS decimal(3, 1)) AS Hour
, COUNT(T.BookingID) AS NoOfUsers
FROM intervals
LEFT JOIN dbo.tbl_Visitor T
ON T.TimeofArrival >= intervals.interval
AND T.TimeofArrival < DATEADD(minute, #IntervalMinutes, intervals.interval)
WHERE
interval >= DATEADD(minute, DATEDIFF(minute, '', #IntervalStartTime), #DateTimeToFilter)
AND interval < DATEADD(minute, DATEDIFF(minute, '', #IntervalEndTime), #DateTimeToFilter)
GROUP BY interval
ORDER BY Hour;

Resources