How to maintain - sql

I'm wondering if SQL Server (i.e. the T-SQL language) has a natural way of doing this or if I have to write fancy constraints/triggers.
Suppose I have a table
RebuplicanCandidates
===================================
Id | Name | ByteIndex
===================================
1 | 'Marco Rubio' | 0
2 | 'Jeb Bush' | 1
3 | 'Donald Trump' | 2
4 | 'Ted Cruz' | 3
and I remove JebBush:
DELETE FROM [RepublicanCandidates] WHERE [Id]=2
Then I want the table to be like
RebuplicanCandidates
===================================
Id | Name | ByteIndex
===================================
1 | 'Marco Rubio' | 0
3 | 'Donald Trump' | 1
4 | 'Ted Cruz' | 2
Notice that the ByteIndex column shuffled.
And then if I insert a candidate
INSERT INTO [RepublicanCandidates] (Name) VALUES ('CarlyFiorina')
the table becomes
RebuplicanCandidates
===================================
Id | Name | ByteIndex
===================================
1 | 'Marco Rubio' | 0
3 | 'Donald Trump' | 1
4 | 'Ted Cruz' | 2
5 | 'Carly Fiorina' | 3

If you created a VIEW based on the table, you could add a row_number() function, and drop the ByteIndex column from the base table.
CREATE VIEW vRebuplicanCandidates
AS
SELECT id, name , ROW_NUMBER() OVER (ORDER BY id) - 1 AS ByteIndex
FROM RebuplicanCandidates

T-SQL cannot do what your are asking. You will have to write some code or the suggestion in the other answer by is a good one IMHO.

Related

SELECT 1 ID and all belonging elements

I try to create a json select query which can give me back the result on next way.
1 row contains 1 main_message_id and belonging messages. (Like the bottom image.) The json format is not a requirement, if its work with other methods, it will be fine.
I store the data as like this:
+-----------------+---------+----------------+
| main_message_id | message | sub_message_id |
+-----------------+---------+----------------+
| 1 | test 1 | 1 |
| 1 | test 2 | 2 |
| 1 | test 3 | 3 |
| 2 | test 4 | 4 |
| 2 | test 5 | 5 |
| 3 | test 6 | 6 |
+-----------------+---------+----------------+
I would like to create a query, which give me back the data as like this:
+-----------------+-----------------------+--+
| main_message_id | message | |
+-----------------+-----------------------+--+
| 1 | {test1}{test2}{test3} | |
| 2 | {test4}{test5}{test6} | |
| 3 | {test7}{test8}{test9} | |
+-----------------+-----------------------+--+
You can use json_agg() for that:
select main_message_id, json_agg(message) as messages
from the_table
group by main_message_id;
Note that {test1}{test2}{test3} is invalid JSON, the above will return a valid JSON array e.g. ["test1", "test2", "test3"]
If you just want a comma separated list, use string_agg();
select main_message_id, string_ag(message, ', ') as messages
from the_table
group by main_message_id;

How to add data or change schema to production database

I am new to working with databases and I want to make sure I understand the best way to add or remove data from a database without making a mess of any related data.
Here is a scenario I am working with:
I have a Tags table, with an Identity ID column. The Tags can be selected via the web application to categorize stories that are submitted by a user. When the database was first seeded; like tags were seeded in order together. As you can see all the Campuses (cities) were 1-4, the Colleges (subjects) are 5-7, and Populations are 8-11.
If this database is live in production and the client wants to add a new Campus (City) tag, what is the best way to do this?
All the other city tags are sort of organized at the top, it seems like the only option is to insert any new tags at to bottom of the table, where they will end up taking whatever the next ID available is. I suppose this is fine because the Display category column will allow us to know which categories these new tags actually belong to.
Is this typical? Is there better ways to set up the database or handle this situation such that everything remains more organized?
Thank you
+----+------------------+---------------+-----------------+--------------+--------+----------+
| ID | DisplayName | DisplayDetail | DisplayCategory | DisplayOrder | Active | ParentID |
+----+------------------+---------------+-----------------+--------------+--------+----------+
| 1 | Albany | NULL | 1 | 0 | 1 | NULL |
| 2 | Buffalo | NULL | 1 | 1 | 1 | NULL |
| 3 | New York City | NULL | 1 | 2 | 1 | NULL |
| 4 | Syracuse | NULL | 1 | 3 | 1 | NULL |
| 5 | Business | NULL | 2 | 0 | 1 | NULL |
| 6 | Dentistry | NULL | 2 | 1 | 1 | NULL |
| 7 | Law | NULL | 2 | 2 | 1 | NULL |
| 8 | Student-Athletes | NULL | 3 | 0 | 1 | NULL |
| 9 | Alumni | NULL | 3 | 1 | 1 | NULL |
| 10 | Faculty | NULL | 3 | 2 | 1 | NULL |
| 11 | Staff | NULL | 3 | 3 | 1 | NULL |
+----+------------------+---------------+-----------------+--------------+--------+----------+
The terms "top" and "bottom" which you use aren't really applicable. "Albany" isn't at the "Top" of the table - it's merely at the top of the specific view you see when you query the table without specifying a meaningful sort order. It defaults to a sort order based on the Id or an internal ROWID parameter, which isn't the logical way to show this data.
Data in the table isn't inherently ordered. If you want to view your tags organized by their category, simply order your query by DisplayCategory (and probably by DisplayOrder afterwards), and you'll see your data properly organized. You can even create a persistent View that sorts it that way for your convenience.

Compare two columns and return the result in a thrid

Lets say I have this table :
--------------------------------------------------------------------------
| id | allowed_to_play_pokemon_go_after | last_played_pokemon_go | name |
--------------------------------------------------------------------------
| 1 | 20-JUL-16 | 19-JUL-16 | Jhon |
--------------------------------------------------------------------------
| 2 | 19-JUL-16 | 21-JUL-16 | Bill |
--------------------------------------------------------------------------
Now I want to make a select like that :
SELECT name, (last_played_pokemon_go > allowed_to_play_pokemon_go_after) as must_punish
FROM myTable;
Where 'must_punish' has to bo a boolean (1/0).
You can use case:
SELECT name,
(case when last_played_pokemon_go > allowed_to_play_pokemon_go_after then 1 else 0
end) as must_punish
FROM myTable;
Oracle (the database) doesn't have a boolean data type. A number should be fine.

Multiple Column Constraint [duplicate]

This question already has answers here:
Simple CHECK Constraint not so simple
(2 answers)
Closed 8 years ago.
I have a table with three columns, the ID of the relation, the ID of the object related and the value of the object. The table may have as many repeated ID-Value relations except when the Value is 0 for the same ID.
Correct Incorrect
+--------+--------+-------+ +--------+--------+-------+
| PK_ID | ID | Value | | PK_ID | ID | Value |
+--------+--------+-------+ +--------+--------+-------+
| 1 | 1 | 1 | | 1 | 1 | 1 |
| 2 | 1 | 1 | | 2 | 1 | 1 |
| 3 | 2 | 0 | | 3 | 2 | 0 |
+--------+--------+-------+ | 4 | 2 | 0 |
+--------+--------+-------+
The question is how can I enforce it not to allow a repeated ID-Value relation when the value is 0?
As pointed out by #Martin Smith in the comments of the question this is indeed similar to Simple CHECK Constraint not so simple and in the answer to that question (although it was for sql-08) there's an example solution for sql-00 and 05.
The idea is to create an index view to simulate a filtered unique index with the following code:
CREATE VIEW dbo.myTableView
WITH SCHEMABINDING
AS
SELECT ID
FROM dbo.myTable
WHERE Value = 0
GO
CREATE UNIQUE CLUSTERED INDEX ix ON dbo.myTableView(ID)

Is there a single query that can update a "sequence number" across multiple groups?

Given a table like below, is there a single-query way to update the table from this:
| id | type_id | created_at | sequence |
|----|---------|------------|----------|
| 1 | 1 | 2010-04-26 | NULL |
| 2 | 1 | 2010-04-27 | NULL |
| 3 | 2 | 2010-04-28 | NULL |
| 4 | 3 | 2010-04-28 | NULL |
To this (note that created_at is used for ordering, and sequence is "grouped" by type_id):
| id | type_id | created_at | sequence |
|----|---------|------------|----------|
| 1 | 1 | 2010-04-26 | 1 |
| 2 | 1 | 2010-04-27 | 2 |
| 3 | 2 | 2010-04-28 | 1 |
| 4 | 3 | 2010-04-28 | 1 |
I've seen some code before that used an # variable like the following, that I thought might work:
SET #seq = 0;
UPDATE `log` SET `sequence` = #seq := #seq + 1
ORDER BY `created_at`;
But that obviously doesn't reset the sequence to 1 for each type_id.
If there's no single-query way to do this, what's the most efficient way?
Data in this table may be deleted, so I'm planning to run a stored procedure after the user is done editing to re-sequence the table.
You can use another variable storing the previous type_id (#type_id). The query is ordered by type_id, so whenever there is a change in type_id, sequence has to be reset to 1 again.
Set #seq = 0;
Set #type_id = -1;
Update `log`
Set `sequence` = If(#type_id=(#type_id:=`type_id`), (#seq:=#seq+1), (#seq:=1))
Order By `type_id`, `created_at`;
I don't know MySQL very well, but you could use a sub query though it may be very slow.
UPDATE 'log' set 'sequence' = (
select count(*) from 'log' as log2
where log2.type_id = log.type_id and
log2.created_at < log.created_at) + 1
You'll get duplicate sequences, though, if two type_ids have the same created_at date.