T-SQL Trigger Update with conditions - tsql

is it possible to block an update of a field based on a condition?
I have a table: sizes
article
shoe_type
size
shoes
0
0
pants
null
0
outerwear
null
0
If the article is "shoes" and "shoe_type" is 0, it cannot be saved if the value 0 is not changed first. (0 must not remain)
If the article is "shoes" and "sizes" is 0, it cannot be saved if the value 0 is not changed first. (0 must not remain)
If the article is "pants" and "sizes" is 0, it cannot be saved if the value 0 is not changed first. (0 must not remain)
If the article is "outerwear" and "sizes" is 0, it cannot be saved if the value 0 is not changed first. (0 must not remain).

One way:
create trigger sizes__shoe_stuff
after update
as begin
if exists
(
select
from
inserted i
inner join deleted d on i.article=d.article -- I assume article is the PK. If not, join i and d on all PK columns
where
(
(d.article='shoes' and d.shoe_type=0 and i.shoe_type <>0)
or (d.article in ('shoes','pants','outerwear') and d.size=0 and i.size <>0)
)
)
throw 'Trigger error, value 0 must change'
end

Related

Why `IF` clause is not possible in postgres `CHECK` constraint?

for example is this query possible?
CREATE TABLE products (
name text,
price numeric not null,
CHECK (IF price > 0 THEN name IS NOT NULL ELSE name IS NULL END IF)
);
UPDATE:
seems like no
here https://rextester.com/l/postgresql_online_compiler
it throws error
Error(s), warning(s):
42601: syntax error at or near "price"
looking at documentation https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-EXCLUDE it says
Currently, CHECK expressions cannot contain subqueries nor refer to variables other than columns of the current row. The system column tableoid may be referenced, but not any other system column.
but IF is not subquery, dont understand why it doesnt work
UPDATE 2:
the
CREATE TABLE products (
name text,
price numeric not null,
CHECK ((price > 0 AND name IS NOT NULL) OR (price <= 0 AND name IS NULL))
);
works, but it makes tedious to write complex queries this way
IF is not a subquery, and it is not anything else either, in SQL. So it is assumed to be a column name. Having two (assumed) column names immediately in a row is a syntax error, and is assigned to the second column name.
SQL has CASE, not IF. You need to use the language you are using, not just make up things you hope to work.
CREATE TABLE products (
name text,
price numeric not null,
CHECK (case when price > 0 THEN name IS NOT NULL ELSE name IS NULL END)
);
I'm not 100% on what you're asking, but I think you're saying:
If the price > 0 then name CANNOT be NULL
In which case this should do it:
CHECK (price > 0 AND name IS NOT NULL)
If the name can be NULL on price being 0 then use this:
CHECK ((price > 0 AND name IS NOT NULL) OR (price = 0 AND name IS NULL))
You don't need to specify IF in the CHECK condition, it should essentially contain the actual statement to be tested rather than an IF statement.

Postgres `ON CONFLICT` updates a variable instead of a TABLE, syntax error at or near ""

I created a postgres query that inserts a series of unique codes. If one code is a duplicate I run the following.
ON CONFLICT ON CONSTRAINT uniquecode DO NOTHING;
What I want to do instead of NOTHING is "counter" = "counter" - 1; because within my while loop "counter" is always incremented by 1. If there is a duplicate then I want it reduced so that if I pass in 10 as the number of generated codes, then it will always return 10 unique codes instead of 9 sometimes because one was a duplicate.
However, I receive the following error when I replaceDO NOTHING or NOTHING with the counter reduction.
syntax error at or near "count"
What is this syntax error. All examples I have seen online show table updates instead. Can I simple update a variable instead?
As per the link posted by #a_horse_with_no_name I tried to apply the below after the conflict.
ON CONFLICT ON CONSTRAINT uniquecode DO UPDATE SET "created_at" = NOW();
PERFORM * FROM (
SELECT c."created_at"
FROM "codes" as c
ORDER BY "created_at" DESC
LIMIT 1
) AS "newest";
IF ("newest"::xmax::text::int > 0) THEN
"counter" = "counter" - 1;
END IF;
The intention of the above is that I only reduce the counter if the xmax greater than zero, which means that it was updated not inserted. If updated then that means that "created_at" was changed in the conflict, else do nothing.
Currently, I am at a point where if I keep the PERFORM call then either "type" xmax does not exist or "column" xmax does not exist.
You might use:
ON CONFLICT ON CONSTRAINT uniquecode
DO UPDATE SET count = youtable.column - 1
GET DIAGNOSTICS "found" = ROW_COUNT;
IF ("found" = true) THEN "count" = "count" + 1; END IF;
The above solved my problem. It checks if there was change in the previous code block, if not, then it won't update.

Count the number of occurrences of Null in a column in tableau

I am relatively new to Tableau and I am wondering if there is a way to calculate null values in a column.
I have a column called Email of type string and want to know how many people have not entered their email i.e. Null.
I tried to create a calculated field with
count(ISNULL([Email]))
But this gives me the total count and not the count of null.
Thanks.
You cannot count NULL since COUNT ignores NULLs.
You can do this, though:
SUM(IF ISNULL([Email]) THEN 1 ELSE 0 END)
Per your additional comment, if you wanted to count where two fields are both NULL then:
SUM(IF ISNULL([Email]) AND ISNULL([Phone]) THEN 1 ELSE 0 END)
You can continue this for any number of fields, as needed.
You can use a filter for that field. Set it to only show you Null values, and set the measure to Count instead of the default Sum.
You can create another column where all null values are set to 1 and anything else to 0, >then count that. It should be something like
>COUNT(IF "null" THEN 1 ELSE 0)
A working syntax for that would had been:
SUM(IF ([Your field] = null) THEN 1
ELSE 0
END)
You can create another column where all null values are set to 1 and anything else to 0, then count that. It should be something like
COUNT(IF "null" THEN 1 ELSE 0)

Postgres bitmask group by

I have the following flags declared:
0 - None
1 - Read
2 - Write
4 - View
I want to write a query that will group on this bitmask and get the count of each flag used.
person mask
a 0
b 3
c 7
d 6
The result should be:
flag count
none 1
read 2
write 3
view 2
Any tips would be appreciated.
For Craig
SELECT lea.mask as trackerStatusMask,
count(*) as count
FROM Live le
INNER JOIN (
... --some guff
) lea on le.xId = lea.xId
WHERE le.xId = p_xId
GROUP BY lea.mask;
SQL Fiddle
select
count(mask = 0 or null) as "None",
count(mask & 1 > 0 or null) as "Read",
count(mask & 2 > 0 or null) as "Write",
count(mask & 4 > 0 or null) as "View"
from t
Simplest - pivoted result
Here's how I'd approach it:
-- (after fixing the idiotic mistakes in the first version)
SELECT
count(nullif(mask <> 0, True)) AS "none",
count(nullif(mask & 2,0)) AS "write",
count(nullif(mask & 1,0)) AS "read",
count(nullif(mask & 4,0)) AS "view"
FROM my_table;
-- ... though #ClodAldo's version of it below is considerably clearer, per comments.
This doesn't do a GROUP BY as such; instead it scans the table and collects the data in a single pass, producing column-oriented results.
If you need it in row form you can pivot the result, either using the crosstab function from the tablefunc module or by hand.
If you really must GROUP BY, explode the bitmask
You cannot use GROUP BY for this in a simple way, because it expects rows to fall into exactly one group. Your rows appear in multiple groups. If you must use GROUP BY you will have to do so by generating an "exploded" bitmask where one input row gets copied to produce multiple output rows. This can be done with a LATERAL function invocation in 9.3, or with a SRF-in-SELECT in 9.2, or by simply doing a join on a VALUES clause:
SELECT
CASE
WHEN mask_bit = 1 THEN 'read'
WHEN mask_bit = 2 THEN 'write'
WHEN mask_bit = 4 THEN 'view'
WHEN mask_bit IS NULL THEN 'none'
END AS "flag",
count(person) AS "count"
FROM t
LEFT OUTER JOIN (
VALUES (4),(2),(1)
) mask_bits(mask_bit)
ON (mask & mask_bit = mask_bit)
GROUP BY mask_bit;
I don't think you'll have much luck making this as efficient as a single table scan, though.

How do return a Constant Value in the Sql Else Clause when only on value remain's the same

UPDATE ConcordWholesales_new.dbo.Product
SET CCCQTYINSTOCK=isnull(#newQTYINSTOCK,'')
where SKU=#newSTOCKCODE
UPDATE Product
SET Published = CASE WHEN CCCQTYINSTOCK=isnull(#newQTYINSTOCK,'')
THEN '1' ELSE 0 END
I have an Update Trigger that Update's Stock Quantity's when its below 0 the Product becomes Unpublished. If the StockQuantity goes above 0 the above Case Updates the Published feild to republish the Product.
When I update the ELSE clause returns a 0 value on the other columns, but If I remove the ELSE clause it can't insert a null value.
How do I return the above code so it only Updates one line of data.
you were missing WHERE clause in second statement
UPDATE Product
SET Published = CASE WHEN CCCQTYINSTOCK > 0
THEN 1 ELSE 0 END
where SKU=#newSTOCKCODE
and one more thing, what datatype is Published column ?
you are using '1' - its nchar, and 0 - int