Grouping by a column to compare values between similar rows - sql

I'm trying to turn this
+----+---------+-------------------+-----------+
| id | year | desc | amount |
+----+---------+-------------------+-----------+
| 1 | 2017 | car | 500 |
| 2 | 2017 | car | 550 |
| 1 | 2018 | car | 490 |
| 2 | 2018 | car | 550 |
| 1 | 2017 | house | 200 |
| 2 | 2017 | house | 300 |
| 1 | 2018 | house | 210 |
| 2 | 2018 | house | 320 |
| 1 | 2019 | house | 290 |
| 2 | 2019 | house | 325 |
+----+---------+-------------------+-----------+
Into something like this
+----+---------+---------+-------------------+-----------+-----------+
| id | year_0 | year_1 | desc | amount_0 | amount_1 |
+----+---------+---------+-------------------+-----------+-----------+
| 1 | 2017 | 2018 | car | 500 | 490 |
| 2 | 2017 | 2018 | car | 550 | 550 |
| 1 | 2017 | 2018 | house | 200 | 210 |
| 2 | 2017 | 2018 | house | 300 | 320 |
+----+---------+---------+-------------------+-----------+-----------+
But I'm having difficulty getting the two years and two amounts to group by description.

You can achieve the result by applying join:
SELECT A.id,a.year year_0,b.year year_1, A.[desc], A.amount amount_0,B.amount amount_1
FROM
(SELECT * FROM YourTable WHERE Year= Datepart(year,GETDATE())-1) AS A
INNER JOIN
(SELECT * FROM YourTable WHERE Year= Datepart(year,GETDATE())) AS B
ON A.id=B.id AND A.[desc]=B.[desc]

Related

Get aggregate quantity from JOINED tables

I have the following two tables in my database
inventory_transactions table
id | date_created | company_id | product_id | quantity | amount | is_verified | buy_or_sell_to | transaction_type | parent_tx | invoice_id | order_id | transaction_comment
----+----------------------------+------------+------------+----------+--------+-------------+----------------+------------------+-----------+------------+----------+---------------------
1 | 2022-04-25 10:42:00.627495 | 20 | 100 | 23 | 7659 | t | | BUY | | 1 | |
2 | 2022-04-25 10:48:48.02342 | 21 | 2 | 10 | 100 | t | | BUY | | 2 | |
3 | 2022-04-25 11:00:11.624176 | 21 | 7 | 10 | 100 | t | | BUY | | 3 | |
4 | 2022-04-25 11:08:14.607117 | 23 | 1 | 11 | 1210 | t | | BUY | | 4 | |
5 | 2022-04-25 11:13:24.084845 | 23 | 28 | 16 | 2560 | t | | BUY | | 5 | |
6 | 2022-04-25 11:26:56.338881 | 23 | 28 | 15 | 3525 | t | 5 | BUY | | 6 | 1 |
7 | 2022-04-25 11:26:56.340112 | 5 | 28 | 15 | 3525 | t | 23 | SELL | 6 | 6 | 1 |
8 | 2022-04-25 11:30:08.529288 | 23 | 30 | 65 | 15925 | t | 5 | BUY | | 7 | 2 |
9 | 2022-04-25 11:30:08.531005 | 5 | 30 | 65 | 15925 | t | 23 | SELL | 8 | 7 | 2 |
14 | 2022-04-25 12:28:51.658902 | 23 | 28 | 235 | 55225 | t | 5 | BUY | | 11 | 5 |
15 | 2022-04-25 12:28:51.660478 | 5 | 28 | 235 | 55225 | t | 23 | SELL | 14 | 11 | 5 |
20 | 2022-04-25 13:01:31.091524 | 20 | 4 | 4 | 176 | t | | BUY | | 15 | |
10 | 2022-04-25 11:50:48.4519 | 21 | 38 | 1 | 10 | t | | BUY | | 8 | |
11 | 2022-04-25 11:50:48.454118 | 21 | 36 | 1 | 10 | t | | BUY | | 8 | |
12 | 2022-04-25 11:52:19.827671 | 21 | 29 | 1 | 10 | t | | BUY | | 9 | |
13 | 2022-04-25 11:53:16.699881 | 21 | 74 | 1 | 10 | t | | BUY | | 10 | |
16 | 2022-04-25 12:37:39.739125 | 20 | 1 | 228 | 58824 | t | | BUY | | 12 | |
17 | 2022-04-25 12:37:39.741106 | 20 | 3 | 228 | 58824 | t | | BUY | | 12 | |
18 | 2022-04-25 12:49:09.922686 | 21 | 41 | 10 | 1000 | t | | BUY | | 13 | |
19 | 2022-04-25 12:55:11.986451 | 20 | 5 | 22 | 484 | t | | BUY | | 14 | |
NOTE each transaction in the inventory_transactions table is recorded twice with the company_id and buy_or_sell_to swapped for the 2nd row and transaction_type BUY or SELL reserved. (similar to how a journal is menatained in accounting).
db# select * from inventory_transactions where buy_or_sell_to is not Null order by date_created limit 50;
id | date_created | company_id | product_id | quantity | amount | is_verified | buy_or_sell_to | transaction_type | parent_tx | invoice_id | order_id | transaction_comment
----+----------------------------+------------+------------+----------+--------+-------------+----------------+------------------+-----------+------------+----------+---------------------
6 | 2022-04-25 11:26:56.338881 | 23 | 28 | 15 | 3525 | t | 5 | BUY | | 6 | 1 |
7 | 2022-04-25 11:26:56.340112 | 5 | 28 | 15 | 3525 | t | 23 | SELL | 6 | 6 | 1 |
8 | 2022-04-25 11:30:08.529288 | 23 | 30 | 65 | 15925 | t | 5 | BUY | | 7 | 2 |
9 | 2022-04-25 11:30:08.531005 | 5 | 30 | 65 | 15925 | t | 23 | SELL | 8 | 7 | 2 |
companies table (consider this as the users table, in my project all users are companies)
id | company_type | gstin | name | phone_no | address | pincode | is_hymbee_verified | is_active | district_id | pancard_no
----+--------------+-----------------+-------------+------------+---------+---------+--------------------+-----------+-------------+------------
26 | RETAILER | XXXXXXXXXXXXXXX | ACD LLC | 12345%7898 | AQWSAQW | 319401 | | | 11 | AQWSDERFVV
27 | DISTRIBUTOR | XXXXXXXXXXXXXXX | CDF LLC | 123XX7898 | AGWSAQW | 319201 | | | 13 | AQWSDERFVV
28 | RETAILER | XXXXXXXXXXXXXXX | !## LLC | 1234!67XX9 | AQCCAQW | 319101 | | | 16 | AQWSDERFVV
29 | COMPANY | XXXXXXXXXXXXXXX | ZAZ LLC | 123456S898 | AQWQQQW | 319001 | | | 19 | AQWSDERFVV
Problem statement
The query I am trying to write will fetch quantity sold only to users who are RETAILERs and DISTRIBUTORS by users who are either a RETAILER or a DISTRIBUTOR.
for example, if a user is a RETAILER, we need to calculate how much quantity this RETAILER has sold to other users who are either RETAILER or DISTRIBUTORs.
In other words, for all rows in the companies table check if the company is of company_type, RETAILER or DISTRIBUTOR and from the inventory_transactions table, check how much quantity a partiuclar RETAILER OR DISTRIBUTOR has sold to other RETAILERs and DISTRIBUTORs
I have very basic knowledge of SQL and have only gotten so far:
select Seller.id as Seller_ROW, Buyer.id as Buyer_row, Seller.company_id, Buyer.buy_or_sell_to, Seller.company_type as Seller_Type, Buyer.company_type as Buyer_Type, Seller.quantity, Buyer.quantity
FROM
(select t.id, t.company_id, t.quantity, c.company_type
from inventory_transactions as t
join companies as c on c.id = t.company_id
where c.company_type = 'RETAILER' or company_type = 'DISTRIBUTOR'
) as Seller
JOIN
(select t.id, t.buy_or_sell_to, t.quantity, c.company_type
from inventory_transactions as t
join companies as c on c.id = t.buy_or_sell_to
where c.company_type = 'RETAILER' or company_type = 'DISTRIBUTOR') as Buyer on Seller.id = Buyer.id
output
seller_row | buyer_row | company_id | buy_or_sell_to | seller_type | buyer_type | quantity | quantity
------------+-----------+------------+----------------+-------------+-------------+----------+----------
25 | 25 | 22 | 25 | RETAILER | DISTRIBUTOR | 1 | 1
26 | 26 | 25 | 22 | DISTRIBUTOR | RETAILER | 1 | 1
31 | 31 | 37 | 43 | DISTRIBUTOR | RETAILER | 10 | 10
32 | 32 | 43 | 37 | RETAILER | DISTRIBUTOR | 10 | 10
33 | 33 | 21 | 43 | DISTRIBUTOR | RETAILER | 1 | 1
34 | 34 | 43 | 21 | RETAILER | DISTRIBUTOR | 1 | 1
35 | 35 | 21 | 49 | DISTRIBUTOR | RETAILER | 1 | 1
36 | 36 | 49 | 21 | RETAILER | DISTRIBUTOR | 1 | 1
37 | 37 | 21 | 51 | DISTRIBUTOR | RETAILER | 1 | 1
38 | 38 | 51 | 21 | RETAILER | DISTRIBUTOR | 1 | 1
There are duplicate rows in the resulting table and so i am unable to do a SUM().
Expected result
SELLER.company_id | SELLER.company_name | SELLER.company_type | QUANTITY | BUYER.company_type
26 | XYZ Retail Co. | RETAILER | 14 | RETAILER
26 | XYZ Retail Co. | RETAILER | 1 | DISTRIBUTOR
27 | ACD Distributions | DISTRIBUTOR | 0 | RETAILER
27 | ACD Distributions | DISTRIBUTOR | 10 | DISTRIBUTOR
This answer assumes that every sale is represented as two rows in inventory_transactions, which makes it possible to avoid duplicates by working with only one transaction_type, so we'll filter on SELL transactions.
SELECT t.company_id AS seller_company_id
, s.company_name AS seller_company_name
, s.company_type AS seller_company_type
, SUM(t.quantity) AS quantity
, b.company_type AS buyer_company_type
FROM inventory_transactions AS t
INNER JOIN companies AS s
ON s.id = t.company_id
INNER JOIN companies AS b
ON b.id = buy_or_sell_to
WHERE t.transaction_type = 'SELL'
AND s.company_type IN ('RETAILER','DISTRIBUTOR')
AND b.company_type IN ('RETAILER','DISTRIBUTOR')
GROUP BY t.company_id, s.company_name, s.company_type, b.company_type
ORDER BY seller_company_id, seller_company_name, seller_company_type, buyer_company_type
;

SQL window excluding current group?

I'm trying to provide rolled up summaries of the following data including only the group in question as well as excluding the group. I think this can be done with a window function, but I'm having problems with getting the syntax down (in my case Hive SQL).
I want the following data to be aggregated
+------------+---------+--------+
| date | product | rating |
+------------+---------+--------+
| 2018-01-01 | A | 1 |
| 2018-01-02 | A | 3 |
| 2018-01-20 | A | 4 |
| 2018-01-27 | A | 5 |
| 2018-01-29 | A | 4 |
| 2018-02-01 | A | 5 |
| 2017-01-09 | B | NULL |
| 2017-01-12 | B | 3 |
| 2017-01-15 | B | 4 |
| 2017-01-28 | B | 4 |
| 2017-07-21 | B | 2 |
| 2017-09-21 | B | 5 |
| 2017-09-13 | C | 3 |
| 2017-09-14 | C | 4 |
| 2017-09-15 | C | 5 |
| 2017-09-16 | C | 5 |
| 2018-04-01 | C | 2 |
| 2018-01-13 | D | 1 |
| 2018-01-14 | D | 2 |
| 2018-01-24 | D | 3 |
| 2018-01-31 | D | 4 |
+------------+---------+--------+
Aggregated results:
+------+-------+---------+----+------------+------------------+----------+
| year | month | product | ct | avg_rating | avg_rating_other | other_ct |
+------+-------+---------+----+------------+------------------+----------+
| 2018 | 1 | A | 5 | 3.4 | 2.5 | 4 |
| 2018 | 2 | A | 1 | 5 | NULL | 0 |
| 2017 | 1 | B | 4 | 3.6666667 | NULL | 0 |
| 2017 | 7 | B | 1 | 2 | NULL | 0 |
| 2017 | 9 | B | 1 | 5 | 4.25 | 4 |
| 2017 | 9 | C | 4 | 4.25 | 5 | 1 |
| 2018 | 4 | C | 1 | 2 | NULL | 0 |
| 2018 | 1 | D | 4 | 2.5 | 3.4 | 5 |
+------+-------+---------+----+------------+------------------+----------+
I've also considered producing two aggregates, one with the product in question and one without, but having trouble with creating the appropriate joining key.
You can do:
select year(date), month(date), product,
count(*) as ct, avg(rating) as avg_rating,
sum(count(*)) over (partition by year(date), month(date)) - count(*) as ct_other,
((sum(sum(rating)) over (partition by year(date), month(date)) - sum(rating)) /
(sum(count(*)) over (partition by year(date), month(date)) - count(*))
) as avg_other
from t
group by year(date), month(date), product;
The rating for the "other" is a bit tricky. You need to add everything up and subtract out the current row -- and calculate the average by doing the sum divided by the count.

Why do you need to include a field in GROUP BY when using OVER (PARTITION BY x)?

I have a table for which I want to do a simple sum of a field, grouped by two columns. I then want the total for all values for each year_num.
See example: http://rextester.com/QSLRS68794
This query is throwing: "42803: column "foo.num_cust" must appear in the GROUP BY clause or be used in an aggregate function", and I cannot figure out why. Why would an aggregate function using the OVER (PARTITION BY x) require the summed field to be in GROUP BY??
select
year_num
,age_bucket
,sum(num_cust)
--,sum(num_cust) over (partition by year_num) --THROWS ERROR!!
from
foo
group by
year_num
,age_bucket
order by 1,2
TABLE:
| loc_id | year_num | gen | cust_category | cust_age | num_cust | age_bucket |
|--------|-----------|------|----------------|-----------|-----------|-------------|
| 1 | 2016 | M | cash | 41 | 2 | 04_<45 |
| 1 | 2016 | F | Prepaid | 41 | 1 | 03_<35 |
| 1 | 2016 | F | cc | 61 | 1 | 05_45+ |
| 1 | 2016 | F | cc | 19 | 2 | 02_<25 |
| 1 | 2016 | M | cc | 64 | 1 | 05_45+ |
| 1 | 2016 | F | cash | 46 | 1 | 05_45+ |
| 1 | 2016 | F | cash | 27 | 3 | 03_<35 |
| 1 | 2016 | M | cash | 42 | 1 | 04_<45 |
| 1 | 2017 | F | cc | 35 | 1 | 04_<45 |
| 1 | 2017 | F | cc | 37 | 1 | 04_<45 |
| 1 | 2017 | F | cash | 46 | 1 | 05_45+ |
| 1 | 2016 | F | cash | 19 | 4 | 02_<25 |
| 1 | 2017 | M | cash | 43 | 1 | 04_<45 |
| 1 | 2017 | M | cash | 29 | 1 | 03_<35 |
| 1 | 2016 | F | cc | 13 | 1 | 01_<18 |
| 1 | 2017 | F | cash | 16 | 2 | 01_<18 |
| 1 | 2016 | F | cc | 17 | 2 | 01_<18 |
| 1 | 2016 | M | cc | 17 | 2 | 01_<18 |
| 1 | 2017 | F | cash | 18 | 9 | 02_<25 |
DESIRED OUTPUT:
| year_num | age_bucket | sum | sum over (year_num) |
|----------|------------|-----|---------------------|
| 2016 | 01_<18 | 5 | 21 |
| 2016 | 02_<25 | 6 | 21 |
| 2016 | 03_<35 | 4 | 21 |
| 2016 | 04_<45 | 3 | 21 |
| 2016 | 05_45+ | 3 | 21 |
| 2017 | 01_<18 | 2 | 16 |
| 2017 | 02_<25 | 9 | 16 |
| 2017 | 03_<35 | 1 | 16 |
| 2017 | 04_<45 | 3 | 16 |
| 2017 | 05_45+ | 1 | 16 |
You need to nest the sum()s:
select year_num, age_bucket, sum(num_cust),
sum(sum(num_cust)) over (partition by year_num) --WORKS!!
from foo
group by year_num, age_bucket
order by 1, 2;
Why? Well, the window function is not doing aggregation. The argument needs to be an expression that can be evaluated after the group by (because this is an aggregation query). Because num_cust is not a group by key, it needs an aggregation function.
Perhaps this is clearer if you used a subquery:
select year_num, age_bucket, sum_num_cust,
sum(sum_num_cust) over (partition by year_num)
from (select year_num, age_bucket, sum(num_cust) as sum_num_cust
from foo
group by year_num, age_bucket
) ya
order by 1, 2;
These two queries do exactly the same thing. But with the subquery it should be more obvious why you need the extra aggregation.

How to select tuples that doesn't match two criterias in the same query?

Let's supose I have the following table list_level
| year | cat_id | user_id | id | val_1 | val_2 |
|------|--------|---------|------|-------|--------|
| 2017 | 2 | 141256 | 1501 | ABC | <null> |
| 2017 | 2 | 141256 | 1023 | DRF | <null> |
| 2017 | 1 | 141256 | 882 | TGV | 100 |
| 2016 | 2 | 141256 | 801 | ADG | 90 |
| 2016 | 1 | 141256 | 590 | IKM | 100 |
| 2016 | 1 | 141256 | 480 | EGM | 87 |
| 2015 | 2 | 141256 | 256 | YHX | 70 |
| 2015 | 1 | 141256 | 132 | QWE | 68 |
How do I get the tuples NOT in year = 2017 and NOT in cat_id = 2
I tried
SELECT
*
FROM
LIST_LEVEL
WHERE
YEAR <> '2017'
AND CAT_ID NOT IN (2)
But that query returns
| year | cat_id | user_id | id | val_1 | val_2 |
|------|--------|---------|------|-------|--------|
| 2016 | 1 | 141256 | 590 | IKM | 100 |
| 2016 | 1 | 141256 | 480 | EGM | 87 |
| 2015 | 1 | 141256 | 132 | QWE | 68 |
And I need this result set
| year | cat_id | user_id | id | val_1 | val_2 |
|------|--------|---------|------|-------|--------|
| 2017 | 1 | 141256 | 882 | TGV | 100 |
| 2016 | 2 | 141256 | 801 | ADG | 90 |
| 2016 | 1 | 141256 | 590 | IKM | 100 |
| 2016 | 1 | 141256 | 480 | EGM | 87 |
| 2015 | 2 | 141256 | 256 | YHX | 70 |
| 2015 | 1 | 141256 | 132 | QWE | 68 |
Finally, I ended whith this query but I think it is a bit complex.
SELECT
*
FROM (
SELECT
*
FROM
LIST_LEVEL
WHERE
YEAR <> '2017'
UNION
SELECT
*
FROM
LIST_LEVEL
WHERE
CAT_ID NOT IN (2)
) T
Is there any other way I can write this query?
I think you just want or:
SELECT ll.*
FROM LIST_LEVEL ll
WHERE ll.YEAR <> '2017' OR CAT_ID NOT IN (2) ;
Or, if you prefer:
WHERE NOT (ll.YEAR = '2017' AND CAT_ID IN (2) ) ;
SELECT
*
FROM
LIST_LEVEL
WHERE
YEAR <> '2017'
AND NOT EXISTS(SELECT * FROM
LIST_LEVEL
WHERE CAT_ID IN(2)

How can I do this in SQL in a Single Statement?

I have the following MySQL table:
+---------+------------+------+--------+------+---------+------------+-------+---------+----------+------------+------------+
| Version | Yr_Varient | FY | Period | CoA | Company | Item | Mvt | Ptnr_Co | Investee | GC | LC |
+---------+------------+------+--------+------+---------+------------+-------+---------+----------+------------+------------+
| 201 | 1 | 2010 | 1 | 11 | 23 | 1110105000 | 60200 | | | 450000 | 450000 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 2110300000 | 60200 | | | -520000 | -520000 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 1220221600 | | | | 78080 | 78080 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 2130323000 | | | | 50000 | 50000 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 2130322000 | | | | -58080 | -58080 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 3100505000 | | | | -275000 | -275000 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 3200652500 | | | | 216920 | 216920 |
| 201 | 1 | 2010 | 1 | 11 | 23 | 3900000000 | | | | 58080 | 58080 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 1110105000 | 60200 | | | 376000 | 376000 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 2110300000 | 60200 | | | -545000 | -545000 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 1220221600 | | | | 452250 | 452250 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 2130323000 | | | | -165000 | -165000 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 2130322000 | | | | -118250 | -118250 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 3100505000 | | | | -937750 | -937750 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 3200652500 | | | | 819500 | 819500 |
| 201 | 1 | 2010 | 1 | 11 | 26 | 3900000000 | | | | 118250 | 118250 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 1110105000 | 60200 | | | 777000 | 777000 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 2110308000 | 60200 | 43 | | -255000 | -255000 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 2130321500 | | | | 180000 | 180000 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 2130322000 | | | | -77000 | -77000 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 2310407001 | | 1 | | -625000 | -625000 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 3100505000 | | | | -2502500 | -2502500 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 3200652500 | | | | 2425500 | 2425500 |
| 201 | 1 | 2010 | 1 | 11 | 37 | 3900000000 | | | | 77000 | 77000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1110105000 | 60200 | | | 2600000 | 2600000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1140161000 | 60200 | | 23 | 430000 | 430000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1140161000 | 60200 | | 26 | 505556 | 505556 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1140160000 | 60200 | 37 | | 255000 | 255000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1160163000 | 60200 | 99999 | 48 | 49428895 | 49428895 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1160163000 | 60200 | 99999 | 49 | 188260175 | 188260175 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 2310405500 | | | | -237689070 | -237689070 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 2110300000 | 60200 | | | -1000 | -1000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 2110300500 | 60200 | | | -3999000 | -3999000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 1220221600 | | | | 1571112 | 1571112 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 2130321500 | | | | -805556 | -805556 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 2130322000 | | | | -556112 | -556112 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 3100505000 | | | | -836000 | -836000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 3200652500 | | | | 781000 | 781000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 3300715700 | | 99999 | 32 | -440000 | -440000 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 3300715700 | | 99999 | 26 | -61112 | -61112 |
| 201 | 1 | 2010 | 1 | 11 | 43 | 3900000000 | | | | 556112 | 556112 |
+---------+------------+------+--------+------+---------+------------+-------+---------+----------+------------+------------+
I need to take all rows with Mvt = 60200 and multiply every GC and LC record in that row by 1.1 and add a new row containing the changes back into the same table with FY set to 2011.
How can I do all this in 1 statement?
Is it even possible to do all this in 1 statement (I know very little about SQL)?
Can this be done in standard SQL as the database will be ported to another Database Server?
I don't know which server it will be.
In standard SQL (there may be better ways in vendor-specific implementations but I tend to prefer standard stuff where possible):
insert into mytable (
Version, Yr_Varient, Period, CoA, Company, Item, Mvt, Ptnr_Co, Investee,
FY, GC, LC
) select
Version, Yr_Varient, Period, CoA, Company, Item, Mvt, Ptnr_Co, Investee,
2011, GC*1.1, LC*1.1
from mytable
where Mvt = 60200
-- and FY = 2010
You may also want to limit your select statement a little more depending on the results of your testing, such as uncommenting the and FY = 2010 line above to stop copying all your 2009 and 2008 data as well, if any. I asume you only wanted to carry forward the previous year's stuff with a 10% increase on GC and LC.
The way this works is to run the select which gives modified data for FY, GC and LC as per your request, and pump all those rows back into the insert.
insert into mytable (
Version,Yr_Varient,FY,Period,CoA,Company,Item,Mvt,Ptnr_Co,Investee,GC,LC)
SELECT Version ,Yr_Varient,"2011" as FY, Period, CoA, Company , Item , Mvt ,Ptnr_Co , Investee , GC*1.1 as GC, LC*1.1 as LC FROM <table Name>
WHERE Mvt = 60200
INSERT INTO _table_
(Version,
Yr_Varient,
FY,
Period,
CoA,
Company,
Item,
Mvt,
Ptnr_Co,
Investee,
GC,
LC)
SELECT
Version,
Yr_Varient,
2011,
Period,
CoA,
Company,
Item,
Mvt,
Ptnr_Co,
Investee,
GC * 1.1,
LC * 1.1
FROM
_table_
WHERE
Mvt = 60200
AND FY <> 2011
This statement should work in any SQL-Database.
Edit: Too slow