Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have a table request_track that saves various security related requests.
Unsuccessful and successful logins have to be saved each and the entry in the request_track table marked as such. Now I struggle to find a good name (for #2) and wanted to know what you guys would do at my place.
I thought about the following options:
Option 1
Make two TINYINT columns: is_login_success and is_login_failure default 0.
Pros
It is very clear
Handy to work with later when retrieving the data. To compare the failures and successes I can simply use sum(is_login_success) and sum(is_login_failure)
Cons
In the logic only one of the two will be set with 1 or both with 0. It is technically possible though to set both with 1 which would cause unpredictable issues in the code.
2 columns when only one could be used to have a similar effect
Option 2
Something like one is_login_success TINYINT default null.
1 would indicate that it was a successful login request, 0 would mean unsuccessful request and null means it's neither.
Pros
Only one column is needed
Cons
It is not clear at all that 0 means explicitly that it's a failure.
To retrieve the data to compare all successes and failures two queries are needed
Option 3
I could make a is_login ENUM('success', 'failure') default null
Pros
Very clear
Only one column
Cons
To retrieve the data to compare all successes and failures two queries are needed (or is there a way to sum the failures and successes and return both with enum?).
My favourite is clearly #3, but I don't want to use two SELECT queries. I'm sure though it's possible in only one. I should have paid more attention in class.
You don't need two queries to fetch the number of successes/failures for any of these cases.
Option 1
Use the SUM function once for each column.
CREATE TABLE request_track (
request_id INT NOT NULL AUTO_INCREMENT,
is_login_success TINYINT NOT NULL,
is_login_failure TINYINT NOT NULL,
PRIMARY KEY ( request_id )
);
SELECT SUM( is_login_success ) AS num_success,
SUM( is_login_failure ) AS num_failure
FROM request_track;
num_success
num_failure
13
2
Option 2
Use the SUM function once for each possible value. Use the CASE function to determine the value to use for each row.
CREATE TABLE request_track (
request_id INT NOT NULL AUTO_INCREMENT,
is_login_success TINYINT,
PRIMARY KEY ( request_id )
);
SELECT SUM(CASE WHEN is_login_success = 1 THEN 1 ELSE 0 END) AS num_success,
SUM(CASE WHEN is_login_success = 0 THEN 1 ELSE 0 END) AS num_failure,
SUM(CASE WHEN is_login_success IS NULL THEN 1 ELSE 0 END) AS num_unknown
FROM request_track;
num_success
num_failure
num_unknown
13
2
3
Option 3
Same approach as option 2.
CREATE TABLE request_track (
request_id INT NOT NULL AUTO_INCREMENT,
is_login ENUM('success', 'failure') DEFAULT NULL,
PRIMARY KEY ( request_id )
);
SELECT SUM(CASE WHEN is_login = 'success' THEN 1 ELSE 0 END) AS num_success,
SUM(CASE WHEN is_login = 'failure' THEN 1 ELSE 0 END) AS num_failure,
SUM(CASE WHEN is_login IS NULL THEN 1 ELSE 0 END) AS num_unknown
FROM request_track;
num_success
num_failure
num_unknown
13
2
3
Regardless, your approach should consider
How easy is it to maintain the data?
As you point out, the first option has the potential for invalid data to get into your
table. If a row ends up with 1 in both is_login_success and is_login_failure
then you've lost data.
The second option also has the possibility to lose data. What happens if a query inserts 2 into is_login_success? Without a constraint, the database won't mind, but the row won't make any business sense.
The third option prevents both of these mistakes. There is only one column so a given row cannot be in conflicting states. The column has a pre-determined number of possible values so it cannot be in an invalid state.
How easy is it to maintain the table?
Adding a single column to each row is not complicated, but you mention that this table will be used to track different types of requests. Will you need a new is_<request type> column for each type? Your table has the potential to become quite wide quite quickly.
You might consider cutting each row down to an identifier, a type, and a status. The meaning of the status is allowed to differ between types and can be defined in an external table. When you need to add or remove a type, you are adding or removing an external table instead of adding or removing columns on your table.
I ended up finding a solution for the drawback of option 3 (source).
is_login column:
`is_login` ENUM('success','failure') NULL DEFAULT NULL
Query to retrieve successes and failures amount:
SELECT
SUM(case when rt.is_login like 'success' then 1 else 0 END) login_success,
SUM(case when rt.is_login like 'failure' then 1 else 0 END) login_failure
FROM request_track rt;
Related
I created a table, tblNewParts with 3 columns:
NewCustPart
AddedDate
Handled
and I am trying to FULL JOIN it to an existing table, tblPartsWorkedOn.
tblNewParts is defined to have Handled defaulted to 'N'...
SELECT *
FROM dbo.tblPartsWorkedOn AS BASE
FULL JOIN dbo.tblNewParts AS ADDON ON BASE.[CustPN] = ADDON.[NewCustPart]
WHERE ADDON.[Handled] IS NULL
ORDER BY [CustPN] DESC
And I want the field [Handled] to come back as 'N' instead of NULL when I run the query. The problem is that when there aren't any records in the new table, I get NULL's instead of 'N's.
I saw a SELECT CASE WHEN col1 IS NULL THEN defaultval ELSE col1 END as a mostly suitable answer from here. I am wondering if this will work in this instance, and how would I write that in T-SQL for SQL Server 2012? I need all of the columns from both tables, rather than just the one.
I'm making this a question, rather than a comment on the cited link, so as to not obscure the original link's question.
Thank you for helping!
Name the column (alias.column_name) in select statement and use ISNULL(alias.column,'N').
Thanks
After many iterations I found the answer, it's kind of bulky but here it is anyway. Synopsis:
Yes, the CASE statement does work, but it gives the output as an unnamed column. Also, in this instance to get all of the original columns AND the corrected column, I had to use SELECT *, CASE...END as [ColumnName].
But, here is the better solution, as it will place the information into the correct column, rather than adding a column to the end of the table and calling that column 'Unnamed Column'.
Select [ID], [Seq], [Shipped], [InternalPN], [CustPN], [Line], [Status],
CASE WHEN ADDON.[NewCustPart] IS NULL THEN BASE.[CustPN] ELSE
ADDON.[NewCustomerPart] END as [NewCustPart],
GetDate() as [AddedDate],
CASE WHEN ADDON.[Handled] IS NULL THEN 'N' ELSE ADDON.[Handled] END as [Handled]
from dbo.tblPartsWorkedOn as BASE
full join dbo.tblNewParts as AddOn ON Base.[CustPN] = AddOn.NewCustPart
where AddOn.Handled = 'N' or AddOn.Handled is null
order by [NewCustPart] desc
This sql code places the [CustPN] into [NewCustPart] if it's null, it puts a 'N' into the field [Handled] if it's null and it assigns the date to the [AddedDate] field. It also only returns records that have not been handled, so that you get the ones that need to be looked at; and it orders the resulting output by the [NewCustPart] field value.
Resulting Output looks something like this: (I shortened the DateTime for the output here.)
[ID] [SEQ] [Shipped] [InternalPN] [CustPN] [Status] [NewCustPart] [AddedDate] [Handled]
1 12 N 10012A 10012A UP 10012A 04/02/2016 N
...
Rather than with the nulls:
[ID] [SEQ] [Shipped] [InternalPN] [CustPN] [Status] [NewCustPart] [AddedDate] [Handled]
1 12 N 10012A 10012A UP NULL NULL NULL
...
I'm leaving this up, and just answering it rather than deleting it, because I am fairly sure that someone else will eventually ask this same question. I think that lots of examples showing how and why something is done, is a very helpful thing to have as not everything can be generalized. Just some thoughts and I hope that this helps someone else!
I've written an Oracle DB Conversion Script that transfers Data from a previous singular table into a new DB with a main table and several child/reference/maintenance tables. Naturally, this more standardized layout (previous could have, say Bob/Storage Room/Ceiling as the [Location] value) has more fields than the old table and thus cannot be exactly converted over.
For the moment, I have inserted a record value (ex.) [NO_CONVERSION_DATA] into each of my child tables. For my main table, I need to set (ex.) [Color_ID] to 22, [Type_ID] to 57 since there is no explicit conversion for these new fields (annually, all of these records are updated, and after the next update all records will exist with proper field values whereupon the placeholder value/record [NO_CONVERSION_DATA] will be removed from the child tables).
I also similarly need to set [Status_Id] something like the following (not working):
INSERT INTO TABLE1 (STATUS_ID)
VALUES
-- Status was not set as Recycled, Disposed, etc. during Conversion
IF STATUS_ID IS NULL THEN
(CASE
-- [Owner] field has a value, set ID to 2 (Assigned)
WHEN RTRIM(LTRIM(OWNER)) IS NOT NULL THEN 2
-- [Owner] field has no value, set ID to 1 (Available)
WHEN RTRIM(LTRIM(OWNER)) IS NULL THEN 1
END as Status)
Can anyone more experienced with Oracle & PL/SQL assist with the syntax/layout for what I'm trying to do here?
Ok, I figured out how to set the 2 specific columns to the same value for all rows:
UPDATE TABLE1
SET COLOR_ID = 24;
UPDATE INV_ASSETSTEST
SET TYPE_ID = 20;
I'm still trying to figure out setting the STATUS_ID based upon the value in the [OWNER] field being NULL/NOT NULL. Coco's solution below looked good at first glace (regarding his comment, not the solution posted, itself), but the below causes each of my NON-NULLABLE columns to flag and the statement will not execute:
INSERT INTO TABLE1(STATUS_ID)
SELECT CASE
WHEN STATUS_ID IS NULL THEN
CASE
WHEN TRIM(OWNER) IS NULL THEN 1
WHEN TRIM(OWNER) IS NOT NULL THEN 2
END
END FROM TABLE1;
I've tried piecing a similar UPDATE statement together, but so far no luck.
Try with this
INSERT INTO TABLE1 (STATUS_ID)
VALUES
(
case
when TATUS_ID IS NULL THEN
(CASE
-- [Owner] field has a value, set ID to 2 (Assigned)
WHEN RTRIM(LTRIM(OWNER)) IS NOT NULL THEN 2
-- [Owner] field has no value, set ID to 1 (Available)
WHEN RTRIM(LTRIM(OWNER)) IS NULL THEN 1
END )
end);
i have a table T with following columns
col1 col2 col3 col4
1 1 1 1
1 1 1 2
1 1 2 1
1 1 2 1
if i set a column col2,col3,col4 as unique. how does the unique works ? will it take uniqueness of combination of each column?
See here: http://www.w3schools.com/sql/sql_unique.asp
The syntax for setting multiple columns as unique is different from that of setting one column unique. If you have multiple columns as unique it is the set that is viewed for uniqueness.
Yes, the "unique-ness" is a result of all columns involved in the constraint. See SO Question
You can easily write yourself a table and test how it handles INSERTs
I'm not entirely sure, but I think the unique attribute has to do with indexing the table. Whichever column you set as unique, that column should be the one you call on to find a certain row. For example in a call like
UPDATE table_name SET column_name = some_value WHERE ID = some_number
the ID column should be set to unique, though I don't know whether not doing so would actually stop you from finding a specific row.
I have a table which I need to update to value of Y, but this update is based upon some results from other tables, and I am not sure how to do this.
Basically, I need to complete the following checks
I need to check from the table I need to update that the other table has exactly 19 matching rows
In those matching rows that one of the fields is not null
I have two other tables which I need to check that records exist in the latter table plus to ensure that the matching records in the latter do not contain the value of "Y" in one of the fields.
My approach to this is to use UNIONs, but I would like someone to advise me whether this approach is correct or whether there is a much better way of doing it:
SELECT '1'
FROM t_A_Outbound
Where NOT HEADER IN (Select HEADER FROM t_B_Outbound)
UNION
SELECT '1'
FROM t_A_Outbound
Where HEADER IN (Select HEADER FROM t_B_Outbound
WHERE NOT INCOMPLETE ='Y')
UNION
Select '1'
From t_C_Outbound
Where ValueString = ''
UNION
Select '1'
From t_C_Outbound
WHERE Exists(Select Count(key), HEADER
From t_C_Outbound IN (SELECT HEADER FROM table_that_needs_updating)
Group By HEADER
Having NOT Count(Cast(key as Int)) = 19)
I thought of using 1 as flag to say if this value comes back to update the field in the table I need to change.
Can anyone advise me?
It is rather unclear to me what unions do for you.
You want an update statement something like:
update table
set y = . . .
where header in (Select header
From t_C_Outbound
Group By HEADER
Having Count(*)= 19 and
count(KEY) = count(*)
) and
header in (select header
from other table
group by header
having sum(case when col = 'Y' then 1 else 0 end) = 0
)
and so on. You don't describe the problem clearly enough to give more detailed code.
i have a table with the column id, itemID and locationId.
i have now split one locationId into multiple ones so i want to:
Update all records where locationId is 10 and have two rows where locationId is set to 11 and 12 (ItemId would be the same for both rows)
So to start i have:
Id ItemID LocationID
1 1 10
and i want to end up with
Id ItemID LocationID
1 1 11
1 1 12
is there any convenient way of doing this given its an update and an insert at once
Possibly there's a single statement that can do it but why wouldn't you just use transactions, a vendor-agnostic way:
begin transaction;
insert into TBL (id,itemid,locationid)
select id, itemid, 11
from TBL
where locationid = 10;
update TBL
set locationid = 12
where locationid = 10;
commit transaction;
I always tend to use standard SQL where possible so as to be able to switch between vendors easily, never mind the fact I haven't switched vendors for over a decade now :-)
Still, it's nice to have the ability even if I never use it (though sometimes I'll go vendor-specific for performance reasons if required - I don't think that'll be necessary for this particular use case since it's probably not something you'll be doing a lot of).