I'm looking for an way to update some rows right after I deleted some rows on MariaDB.
For examples, my talbes are look like:
--------------------------------------
| main_id | name | value | sub_id |
--------------------------------------
| 1 | DRINKS | 1000 | COKE |
| 1 | DRINKS | 2000 | BEER |
| 1 | DRINKS | 0600 | WATER |
| 2 | SALAD | 2000 | Peanut |
| 3 | BREADS | 1500 | FLAT |
| 3 | BREADS | 1000 | TOAST |
| 4 | BEEF | 3000 | SAUSAGE|
...
When I remove '2' SALAD, I want to update every rows main_id to main_id-1 like
--------------------------------------
| main_id | name | value | sub_id |
--------------------------------------
| 1 | DRINKS | 1000 | COKE |
| 1 | DRINKS | 2000 | BEER |
| 1 | DRINKS | 0600 | WATER |
| 2 | BREADS | 1500 | FLAT |
| 2 | BREADS | 1000 | TOAST |
| 3 | BEEF | 3000 | SAUSAGE|
...
// | 2 | SALAD | 2000 | Peanut | has removed so every main_id updated.
I cannot use PRIMARY KEY, because the things are so many duplicated.
If I have to join every rows, then I'm worried about performance, so I cannot find the way to solve the problem.
Thanks for your help.
After the Delete statement :
DELETE FROM t WHERE main_id = 2;
an Update statement containing Analytic Functions might be issued provided your DB version is 10.2+ :
UPDATE t
JOIN (WITH t2 AS
(
SELECT LAG(main_id,1) OVER (ORDER BY main_id) AS lg, t.*
FROM t
)
SELECT t2.*,
1 + SUM(CASE WHEN COALESCE(lg,main_id) = main_id THEN 0 ELSE 1 END )
OVER (ORDER BY main_id) AS new_id
FROM t2 ) t2
ON t.main_id = t2.main_id
SET t.main_id = t2.new_id;
to get main_id - 1 is updated for main_id column for main_id >2 for this individual case.
A Delete Trigger containing an Update cannot be applied on the same because of mutating trigger problem.
Demo
I have a table as follow :
+-------------+-----------+------+
| GroupNumber | TeamName | Goal |
+-------------+-----------+------+
| 1 | Sales | ABC |
| 1 | Sales | ABC |
| 1 | Sales | ABC |
| 1 | Design | XYZ |
| 2 | Design | XYZ |
| 2 | Sales | XYZ |
| 2 | technical | XYZ |
| 2 | Support | XYZ |
| 3 | Sales | XYZ |
| 3 | Sales | XYZ |
| 3 | Sales | XYZ |
+-------------+-----------+------+
I want to output only the groups that have unique teams greater than 3.
Only group 2 has this condition so the output is :
Expected Output:
+-------------+-----------+------+
| GroupNumber | TeamName | Goal |
+-------------+-----------+------+
| 2 | Design | XYZ |
| 2 | Sales | XYZ |
| 2 | technical | XYZ |
| 2 | Support | XYZ |
+-------------+-----------+------+
not sure how to utilize this in subquery
SELECT count(Distinct(TeamName))
FROM mytable
group by [GroupNumber]
HAVING COUNT(Distinct[TeamName])>3
Simply put it in a Subquery:
select *
from mytable
where [GroupNumber] in
(
SELECT [GroupNumber]
FROM mytable
group by [GroupNumber]
HAVING COUNT(Distinct[TeamName])>3
)
Please try
SELECT *
FROM mytable where GroupNumber in (select GroupNumber
FROM mytable group by TeamName
HAVING COUNT(TeamName)>3)
I have a table named payment_info, with the following records.
paymentid | customercode | previousbalance | paymentamount | remainingbalance
-----------------------------------------------------------------------------
PID0001 | CUST024 | 10000 | 2500 | 7500
PID0002 | CUST031 | 8500 | 3500 | 5000
PID0003 | CUST005 | 12000 | 1500 | 10500
Then what I want is to create a 3 rows per row of the above table.
I want my results to look like this.
Payment Group | Payment Line Item | Payment ID | Customer Code | Type | Amount
--------------------------------------------------------------------------------------------------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000.00
1 | 2 | | | PAYMENT AMOUNT | 2500.00
1 | 3 | | | REMAINING BALANCE | 7500.00
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500.00
2 | 2 | | | PAYMENT AMOUNT | 3500.00
2 | 3 | | | REMAINING BALANCE | 5000.00
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000.00
3 | 2 | | | PAYMENT AMOUNT | 1500.00
3 | 3 | | | REMAINING BALANCE | 10500.00
Here is the query I've started. But it did not return results same as above.
select row_number() over() as id,paymentid,customercode,'PREVIOUS BALANCE' as type,previousbalance from payment_info
union
select row_number() over() as id,'','','PAYMENT AMOUNT' as type,paymentamount from payment_info
union
select row_number() over() as id,'','','REMAINING BALANCE' as type,remainingbalance from payment_info
Is there other ways, where I will not use UNION Keyword? Cause in the real table, I will be using 30+ columns, querying thousands of records.
I also don't know how to create auto generated number (id) from payment group (per payment id) and Payment Line Item (per group).
thanks
version with whitespace (empty text)
The unnest function can do this for you.
And if you want the empty text then you can use this
SELECT ROW_NUMBER() OVER (ORDER BY paymentid) AS "group",
unnest(array[1, 2, 3]) AS "line item",
unnest(array[paymentid, '', '']) AS "paymentid",
unnest(array[customercode, '', '']) AS "customercode",
unnest(array['PREVIOUS BALANCE', 'PAYMENT AMOUNT', 'REMAINING BALANCE']) AS "type",
unnest(array[previousbalance, paymentamount, remainingbalance]) AS "amount"
FROM payment_info
ORDER BY 1, 2 ;
To get this
group | line item | paymentid | customercode | type | amount
-------+-----------+-----------+--------------+-------------------+--------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000
1 | 2 | | | PAYMENT AMOUNT | 2500
1 | 3 | | | REMAINING BALANCE | 7500
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500
2 | 2 | | | PAYMENT AMOUNT | 3500
2 | 3 | | | REMAINING BALANCE | 5000
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000
3 | 2 | | | PAYMENT AMOUNT | 1500
3 | 3 | | | REMAINING BALANCE | 10500
If you want to have, for example points or other text, or arrows in the empty text columns, you can do this easily with unnest.
You can control the 4 empty text values individually.
SELECT ROW_NUMBER() OVER (ORDER BY paymentid) AS "group",
unnest(array[1, 2, 3]) AS "line item",
unnest(array[paymentid, ' a', ' c']) AS "paymentid",
unnest(array[customercode, ' b', ' d']) AS "customercode",
unnest(array['PREVIOUS BALANCE', 'PAYMENT AMOUNT', 'REMAINING BALANCE']) AS "type",
unnest(array[previousbalance, paymentamount, remainingbalance]) AS "amount"
FROM payment_info
ORDER BY 1, 2 ;
to generate
group | line item | paymentid | customercode | type | amount
-------+-----------+-----------+--------------+-------------------+--------
1 | 1 | PID0001 | CUST024 | PREVIOUS BALANCE | 10000
1 | 2 | a | b | PAYMENT AMOUNT | 2500
1 | 3 | c | d | REMAINING BALANCE | 7500
2 | 1 | PID0002 | CUST031 | PREVIOUS BALANCE | 8500
2 | 2 | a | b | PAYMENT AMOUNT | 3500
2 | 3 | c | d | REMAINING BALANCE | 5000
3 | 1 | PID0003 | CUST005 | PREVIOUS BALANCE | 12000
3 | 2 | a | b | PAYMENT AMOUNT | 1500
3 | 3 | c | d | REMAINING BALANCE | 10500
It's a very flexible solution, you know.
It isn't necessary to always use union queries. Here for example you can use 3 rows and a cross join instead. This has the advantage of only a single pass over the source table.
drop table if exists Table1;
CREATE TABLE Table1
("paymentid" varchar(7), "customercode" varchar(7)
, "previousbalance" int, "paymentamount" int, "remainingbalance" int)
;
INSERT INTO Table1
("paymentid", "customercode", "previousbalance", "paymentamount", "remainingbalance")
VALUES
('PID0001', 'CUST024', 10000, 2500, 7500),
('PID0002', 'CUST031', 8500, 3500, 5000),
('PID0003', 'CUST005', 12000, 1500, 10500)
;
select
paymentid
, customercode
, rn
, typeof
, case when rn = 1 then previousbalance
when rn = 2 then paymentamount
when rn = 3 then remainingbalance
end as Amount
from Table1
cross join (select 1 rn , 'previousbalance' typeof
union all
select 2 , 'paymentamount'
union all
select 3, 'remainingbalance'
) rns
That data/query produces this result:
+----+-----------+--------------+----+------------------+--------+
| | paymentid | customercode | rn | typeof | amount |
+----+-----------+--------------+----+------------------+--------+
| 1 | PID0001 | CUST024 | 1 | previousbalance | 10000 |
| 2 | PID0001 | CUST024 | 2 | paymentamount | 2500 |
| 3 | PID0001 | CUST024 | 3 | remainingbalance | 7500 |
| 4 | PID0002 | CUST031 | 1 | previousbalance | 8500 |
| 5 | PID0002 | CUST031 | 2 | paymentamount | 3500 |
| 6 | PID0002 | CUST031 | 3 | remainingbalance | 5000 |
| 7 | PID0003 | CUST005 | 1 | previousbalance | 12000 |
| 8 | PID0003 | CUST005 | 2 | paymentamount | 1500 |
| 9 | PID0003 | CUST005 | 3 | remainingbalance | 10500 |
+----+-----------+--------------+----+------------------+--------+
Please then note that SQL isn't a "report writer" so blanks in columns for "layout" are not a good fit for SQL which wants to repeat information (like you see above in the result) so that you can sort and filter as needed.
table: item_tbl
|item_id |serial_code|item_name|
------------------------------
| 1 | x35 | bullet |
| 2 | 6ox | cord |
| 3 | 0hg | cord |
| 4 | a73 | tv |
| 5 | lo5 | bullet |
I tried to use SELECT serial_code, item_name, COUNT(item_name) FROM item_tbl but not what i expected of course. How can I count the distinct values of item_name to have something like:
|serial_code|item_name| count |
-----------------------------
| x35 | bullet | 2 |
| 6ox | cord | 2 |
| 0hg | cord | 2 |
| a73 | tv | 1 |
| lo5 | bullet | 2 |
SELECT Serial_Code, count.Item_Name, Count
FROM
item_tbl i
INNER JOIN
(
SELECT Item_Name, COUNT(1) Count
FROM item_tbl
GROUP BY item_Name
) count ON i.item_Name = count.Item_Name
Lets see if that works.
MSSQL Table1 has following data:
AttributeID | ProductID | Attribute | Value |
--------------------------------------------------
1 | 1111 | Attribute1 | Prod1_Val1 |
2 | 1111 | Attribute2 | Prod1_Val2 |
3 | 1111 | Attribute3 | Prod1_Val3 |
4 | 2222 | Attribute1 | Prod2_Val1 |
5 | 2222 | Attribute2 | Prod2_Val2 |
6 | 2222 | Attribute3 | Prod2_Val3 |
7 | 3333 | Attribute1 | Prod3_Val1 |
8 | 3333 | Attribute2 | Prod3_Val2 |
9 | 3333 | Attribute3 | Prod3_Val3 |
10 | 4444 | Attribute1 | Prod4_Val1 |
11 | 4444 | Attribute2 | Prod4_Val2 |
12 | 5555 | Attribute4 | Prod5_Val1 |
MSSQL Table2 has following Data:
ProductID | ProductName |
--------------------------------------------------
1111 | Product1 |
2222 | Product2 |
3333 | Product3 |
4444 | Product4 |
5555 | Product5 |
The result I would require is:
Product | Product1 | Product3 | Product3 | Product4 | Product5 |
Attribute1 | Prod1_Val1 | Prod2_Val1 | Prod3_Val1 | Prod4_Val1 | -- |
Attribute2 | Prod1_Val2 | Prod2_Val2 | Prod3_Val2 | Prod4_Val2 | -- |
Attribute3 | Prod1_Val3 | Prod2_Val3 | Prod3_Val3 | -- | -- |
Attribute4 | -- | -- | -- | -- | Prod5_Val1 |
Attribute5 | -- | -- | -- | -- | -- |
I would like to know whether this desired result can be achieved with SQL itself using Table1 and Table2. If yes, please assist me by providing the SQL. Thanks for your timely assistance in advance.
As alluded to by TomTom, you will need to use the SQL Server's PIVOT operator:
SELECT Attribute, [Product1], [Product2], [Product3], [Product4], [Product5]
FROM (
SELECT ProductName, Attribute, Value
FROM Table1
INNER JOIN Table2 ON ( Table2.ProductId = Table1.ProductId )
) AS SourceTable
PIVOT (
Min(Value)
FOR ProductName IN ([Product1], [Product2], [Product3], [Product4], [Product5])
) AS PivotTable
Be aware that you will need to decide up front how many columns (that is, [Product1], [Product2], ..., [ProductN]) you would like to output when writing your SQL query.
Also, since PIVOT aggregates data, the example above uses the Min() function. (You could just as easily use Max(), or a different aggregation function, based upon your needs.) Your output will be NULL for all elements that do not have values.