Using MS SQL Server, I want to:
Get data from my application
Perform preprocessing
Update a table
Steps 1 and 3 are giving me problems.
Simplifying the problem to its essence, my existing data looks like:
+--------+-------+
| Item | Usage |
+--------+-------+
| Part A | 10 |
| Part B | 15 |
| Part C | 8 |
+--------+-------+
and an example of the source data is:
+--------+
| Item |
+--------+
| Part A |
| Part B |
| Part B |
| Part B |
| Part A |
| Part A |
+--------+
My over all plan is to import the data into a CTE, do the preprocessing, then do an update.
Regarding getting the data, since "INTO" is not allowed in a CTE, how can I get the source data into the CTE. Or some other approach not using a CTE better?
Preprocessing is straightforward. Here is my SQL:
WITH MyData (Item, NewUsage)
AS
(
<Somehow get the data>
SELECT Item, Count(*) as NewUsage
FROM Items
GROUP BY Item
)
UPDATE Items
SET Usage = Usage + b.NewUsage
FROM Items as a JOIN MyData as b ON a.Item = b.Item;
The update is updating all the rows in Items by 1 instead of using the NewUsage column.
How do I get my data (into the CTE?) and how to write the SQL so it works properly?
Related
I have a spreadsheet which contains multiple tabs with similar layouts. I want to use a formula to merge these into a single tab which has a new column naming the tab it came from.
Example
Tab: Area A
| Item | Status |
|------|-------------|
| Foo | Blocked |
| Bar | In Progress |
Tab: Area B
| Item | Status |
|--------|-----------|
| Foobar | Completed |
Tab: Merged
| Area | Item | Status |
|------|--------|-------------|
| A | Foo | Blocked |
| A | Bar | In Progress |
| B | Foobar | Completed |
Merging without new column
I can merge the data without the additional column, using this formula:
=ARRAYFORMULA(SORT({'Area A'!A2:B; 'Area B'!A2:B}))
Which looks like this:
|--------|-------------|
| Item | Status |
|--------|-------------|
| Foo | Blocked |
| Bar | In Progress |
| Foobar | Completed |
Adding the Area column
What's missing from the above formula is the addition of the area column. This would be possible by cross-referencing the item in every tab using a vlookup and labelling it. But that wouldn't be very efficient and some updates are already slow to re-calculate in this document. I expect this to have approx. 40 tabs with 10,000 rows in total to merge.
Eg:
=IFS(NOT(ISERROR(VLOOKUP(B2,'Area A'!A$2:A,1,FALSE))), "A", NOT(ISERROR(VLOOKUP(B2,'Area B'!A$2:A,1,FALSE))), "B")
Is there a better way to do this?
I'd like something like this, but it doesn't work as the constant I'm adding doesn't match the number of rows it needs to be:
=ARRAYFORMULA(SORT({{"A",'Area A'!A2:B}; {"B", 'Area B'!A2:B}}))
you can borrow empty column and do:
=ARRAYFORMULA(SORT({{'Area A'!X2:X&"A", 'Area A'!A2:B};
{'Area B'!X2:X&"B", 'Area B'!A2:B}}))
or you can add it to first column and then split it:
=ARRAYFORMULA(QUERY(SORT({SPLIT(
{"A♦"&'Area A'!A2:A;
"B♦"&'Area B'!A2:A}, "♦"),
{'Area A'!B2:B;
'Area B'!B2:B}}), "where Col2 is not null", 0))
see: https://stackoverflow.com/a/63496191/5632629
I have a person table which keeps some personal info. like as table below.
+----+------+----------+----------+--------+
| ID | name | motherID | fatherID | sex |
+----+------+----------+----------+--------+
| 1 | A | NULL | NULL | male |
| 2 | B | NULL | NULL | female |
| 3 | C | 1 | 2 | male |
| 4 | X | NULL | NULL | male |
| 5 | Y | NULL | NULL | female |
| 6 | Z | 5 | 4 | female |
| 7 | T | NULL | NULL | female |
+----+------+----------+----------+--------+
Also I keep marriage relationships between people. Like:
+-----------+--------+
| HusbandID | WifeID |
+-----------+--------+
| 1 | 2 |
| 4 | 5 |
| 1 | 5 |
| 3 | 6 |
+-----------+--------+
With these information we can imagine the relationship graph. Like below;
Question is: How can I get all connected people by giving any of them's ID.
For example;
When I give ID=1, it should return to me 1,2,3,4,5,6.(order is not important)
Likewise When I give ID=6, it should return to me 1,2,3,4,5,6.(order is not important)
Likewise When I give ID=7, it should return to me 7.
Please attention : Person nodes' relationships (edges) may have loop anywhere of graph. Example above shows small part of my data. I mean; person and marriage table may consist thousands of rows and we do not know where loops may occur.
Smilar questions asked in :
PostgreSQL SQL query for traversing an entire undirected graph and returning all edges found
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=118319
But I can't code the working SQL. Thanks in advance. I am using SQL Server.
From SQL Server 2017 and Azure SQL DB you can use the new graph database capabilities and the new MATCH clause to answer queries like this, eg
SELECT FORMATMESSAGE ( 'Person %s (%i) has mother %s (%i) and father %s (%i).', person.userName, person.personId, mother.userName, mother.personId, father.userName, father.personId ) msg
FROM dbo.persons person, dbo.relationship hasMother, dbo.persons mother, dbo.relationship hasFather, dbo.persons father
WHERE hasMother.relationshipType = 'mother'
AND hasFather.relationshipType = 'father'
AND MATCH ( father-(hasFather)->person<-(hasMother)-mother );
My results:
Full script available here.
For your specific questions, the current release does not include transitive closure (the ability to loop through the graph n number of times) or polymorphism (find any node in the graph) and answering these queries may involve loops, recursive CTEs or temp tables. I have attempted this in my sample script and it works for your sample data but it's just an example - I'm not 100% it will work with other sample data.
Right now I have dynamic columns based off of a query, and then I have data attached to those columns that I want to populate in rows. They associate just fine, but the problem is that the rows hold whatever place they were in, instead of ascending to the top again, like so:
|column|column2|column3|
| row1 | | |
| | row2 | |
| | | row3 |
And the goal is:
|column|column2|column3|
| row1 | row2 | row3 |
| | | |
| | | |
I know that I could do this in the query, combining the headers with a dynamic query, but is there any SSRS magic that can achieve this without that?
EDIT 1
I am using a matrix, sorry about not specifying, I heard that the only way to do dynamic columns are matrices, so I thought it was implied.
EDIT 2
The rows come in like
Wanted_Column | Wanted Row
Column | data
Column2 | data
Column | data
and I want it so that the table will look like
|column|column2|
| data | data |
| data | |
| | |
for any number of columns/rows
I'm assuming you are using a matrix to do this. It's not clear from your question... Anyway, you'll need to add row grouping. If you don't have data that can be grouped by an actual column value then set the group expression to 1 and that should do it.
If this is not correct then please show you data as it comes from the dataset and the expected output.
EDIT:
Here's what I have: An Access database made up of 3 tables linked from SQL server. I need to create a new table in this database by querying the 3 source tables. Here are examples of the 3 tables I'm using:
PlanTable1
+------+------+------+------+---------+---------+
| Key1 | Key2 | Key3 | Key4 | PName | MainKey |
+------+------+------+------+---------+---------+
| 53 | 1 | 5 | -1 | Bikes | 536681 |
| 53 | 99 | -1 | -1 | Drinks | 536682 |
| 53 | 66 | 68 | -1 | Balls | 536683 |
+------+------+------+------+---------+---------+
SpTable
+----+---------+---------+
| ID | MainKey | SpName |
+----+---------+---------+
| 10 | 536681 | Wing1 |
| 11 | 536682 | Wing2 |
| 12 | 536683 | Wing3 |
+----+---------+---------+
LocTable
+-------+-------------+--------------+
| LocID | CenterState | CenterCity |
+--- ---+-------------+--------------+
| 10 | IN | Indianapolis |
| 11 | OH | Columbus |
| 12 | IL | Chicago |
+-------+-------------+--------------+
You can see the relationships between the tables. The NewMasterTable I need to create based off of these will look something like this:
NewMasterTable
+-------+--------+-------------+------+--------------+-------+-------+-------+
| LocID | PName | CenterState | Key4 | CenterCity | Wing1 | Wing2 | Wing3 |
+-------+--------+-------------+------+--------------+-------+-------+-------+
| 10 | Bikes | IN | -1 | Indianapolis | 1 | 0 | 0 |
| 11 | Drinks | OH | -1 | Columbus | 0 | 1 | 0 |
| 12 | Balls | IL | -1 | Chicago | 0 | 0 | 1 |
+-------+--------+-------------+------+--------------+-------+-------+-------+
The hard part for me is making this new table dynamic. In the future, rows may be added to the source tables. I need my NewMasterTable to reflect any changes/additions to the source. How do I go about building the NewMasterTable as described? Does this make any sort of sense?
Since an Access table is a necessary requirement, then probably the only way to go about it is to create a set of Update and Insert queries that are executed periodically. There is no built-in "dynamic" feature of Access that will monitor and update the table.
First, create the table. You could either 1) do this manually from scratch by defining the columns and constraints yourself, or 2) create a make-table query (i.e. SELECT... INTO) that generates most of the schema, then add any additional columns, edit necessary details and add appropriate indexes.
Define and save Update and Insert (and optional Delete) queries to keep the table synced. I'm not sharing actual code here, because that goes beyond your primary issue I think and requires specifics that you need to define. Due to some ambiguity with your key values (the field names and sample data still are not sufficient to reveal precise relationships and constraints), it is likely that you'll need multiple Update statements.
In particular, the "Wing" columns will likely require a transform statement.
You may not be able to update all columns appropriately using a single query. I recommend not trying to force such an "artificial" requirement. Multiple queries can actually be easier to understand and maintain.
In the event that you experience "query is not updateable" errors, you may need to define other "temporary" tables with appropriate indexes, into which you do initial inserts from the linked tables, then subsequent queries to update your master table from those.
Finally, and I think this is the key to solving your problem, you need to define some Access form (or other code) that periodically runs your set of "sync" queries. Access forms have a [Timer Interval] property and corresponding Timer event that fires periodically. Add VBA code in the Form_Timer sub that runs all your queries. I would suggest "wrapping" such VBA in a transaction and adding appropriate error handling and error logging, etc.
I have a table that stores a group of attributes and keeps them ordered in a sequence. The chance exists that one of the attributes (rows) could be deleted from the table, and the sequence of positions should be compacted.
For instance, if I originally have these set of values:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 2 | two | 2 |
| 3 | three | 3 |
| 4 | four | 4 |
+----+--------+-----+
And the second row was deleted, the position of all subsequent rows should be updated to close the gaps. The result should be this:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 3 | three | 2 |
| 4 | four | 3 |
+----+--------+-----+
Is there a way to do this update in a single query? How could I do this?
PS: I'd appreciate examples for both SQLServer and Oracle, since the system is supposed to support both engines. Thanks!
UPDATE: The reason for this is that users are allowed to modify the positions at will, as well as adding or deleting new rows. Positions are shown to the user, and for that reason, these should show a consistence sequence at all times (and this sequence must be stored, and not generated on demand).
Not sure it works, But with Oracle I would try the following:
update my_table set pos = rownum;
this would work but may be suboptimal for large datasets:
SQL> UPDATE my_table t
2 SET pos = (SELECT COUNT(*) FROM my_table WHERE id <= t.id);
3 rows updated
SQL> select * from my_table;
ID NAME POS
---------- ---------- ----------
1 one 1
3 three 2
4 four 3
Do you really need the sequence values to be contiguous, or do you just need to be able to display the contiguous values? The easiest way to do this is to let the actual sequence become sparse and calculate the rank based on the order:
select id,
name,
dense_rank() over (order by pos) as pos,
pos as sparse_pos
from my_table
(note: this is an Oracle-specific query)
If you make the position sparse in the first place, this would even make re-ordering easier, since you could make each new position halfway between the two existing ones. For instance, if you had a table like this:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 100 |
| 2 | two | 200 |
| 3 | three | 300 |
| 4 | four | 400 |
+----+--------+-----+
When it becomes time to move ID 4 into position 2, you'd just change the position to 150.
Further explanation:
Using the above example, the user initially sees the following (because you're masking the position):
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 2 | two | 2 |
| 3 | three | 3 |
| 4 | four | 4 |
+----+--------+-----+
When the user, through your interface, indicates that the record in position 4 needs to be moved to position 2, you update the position of ID 4 to 150, then re-run your query. The user sees this:
+----+--------+-----+
| id | name | pos |
+----+--------+-----+
| 1 | one | 1 |
| 4 | four | 2 |
| 2 | two | 3 |
| 3 | three | 4 |
+----+--------+-----+
The only reason this wouldn't work is if the user is editing the data directly in the database. Though, even in that case, I'd be inclined to use this kind of solution, via views and instead-of triggers.