Updating multiple rows with a certain value from the same table - tsql

So, I have the next table:
time | name | ID |
12:00:00| access | 1 |
12:05:00| select | null |
12:10:00| update | null |
12:15:00| insert | null |
12:20:00| out | null |
12:30:00| access | 2 |
12:35:00| select | null |
The table is bigger (aprox 1-1,5 mil rows) and there will be ID equal to 2,3,4 etc and rows between.
The following should be the result:
time | name | ID |
12:00:00| access | 1 |
12:05:00| select | 1 |
12:10:00| update | 1 |
12:15:00| insert | 1 |
12:20:00| out | 1 |
12:30:00| access | 2 |
12:35:00| select | 2 |
What is the most simple method to update the rows without making the log full? Like, one ID at a time.

You can do it with a sub query:
UPDATE YourTable t
SET t.ID = (SELECT TOP 1 s.ID
FROM YourTable s
WHERE s.time < t.time AND s.name = 'access'
ORDER BY s.time DESC)
WHERE t.name <> 'access'
Index on (ID,time,name) will help.

You can do it using CTE as below:
;WITH myCTE
AS ( SELECT time
, name
, ROW_NUMBER() OVER ( PARTITION BY name ORDER BY time ) AS [rank]
, ID
FROM YourTable
)
UPDATE myCTE
SET myCTE.ID = myCTE.rank
SELECT *
FROM YourTable ORDER BY ID

Related

2 Level pivot using Postgresql

I have a table whose schema along with data (table_name : raw_data) appears to be this :
name | category | clear_date |
A | GOOD | 2020-05-30 |
A | GOOD | 2020-05-30 |
A | GOOD | 2020-05-30 |
A | GOOD | 2020-05-30 |
A | BAD | 2020-05-30 |
A | BAD | 2020-05-30 |
Now if I perform a "groupby" operation using the following statement :
SELECT name, category, date(clear_date), count(clear_date)
FROM raw_data
GROUP BY name, category, date(clear_date)
ORDER BY name
I get the following answer :
name | caetgory | date | count |
A | GOOD |2020-05-30 | 4 |
A | BAD |2020-05-30 | 1 |
A | BAD |2020-05-31 | 1 |
IN order to produce the pivot in following format :
name | category | 2020-05-30 | 2020-05-31 |
A | GOOD | 4 | NULL |
A | BAD | 1 | 1 |
I am using the following query :
select * from crosstab (
'select name, category, date(clear_date), count(clear_date) from raw_data group by name, category, date(clear_date) order by 1,2,3',
'select distinct date(clear_date) from raw_data order by 1'
)
as newtable (
node_name varchar, alarm_name varchar, "2020-05-30" integer, "2020-05-31" integer
)
ORDER BY name
But I am getting results as follows :
name | category | 2020-05-30 | 2020-05-31 |
A | BAD | 4 | 1 |
Can anyone please try to suggest how can i achieve the result mentioned above. It appears crosstab removes the duplicate entry of A automatically.
Not sure if this is possible using crosstab because you have a missing records in some dates. Here is an example how to get expected result but not sure is what you need. Anyway hope this helps.
SELECT r1.*, r2.counter AS "2020-05-30", r3.counter AS "2020-05-31"
FROM (
SELECT DISTINCT name, category
FROM raw_data
) AS r1
LEFT JOIN (
SELECT name, category, count(*) AS counter
FROM raw_data
WHERE clear_date = '2020-05-30'
GROUP BY name, category
) AS r2 ON (r2.category = r1.category AND r2.name = r1.name)
LEFT JOIN (
SELECT name, category, count(*) AS counter
FROM raw_data
WHERE clear_date = '2020-05-31'
GROUP BY name, category
) AS r3 ON (r3.category = r1.category AND r3.name = r1.name)
ORDER BY r1.category DESC;

Select all columns from two tables

Lets say I have the following:
table_a
| id | date | order_id | sku | price |
--------------------------------------------
| 10 | 2016-08-18 | 111 | ABC | 10 |
table_b
| id | date | order_id | description | type | notes | valid |
-------------------------------------------------------------------
| 50 | 2016-08-18 | 111 | test | AA | | true |
I want to get get all columns from both tables, so the resulting table looks like this:
| id | date | order_id | sku | price | description | type | notes | valid |
---------------------------------------------------------------------------------
| 10 | 2016-08-18 | 111 | ABC | 10 | | | | |
---------------------------------------------------------------------------------
| 50 | 2016-08-18 | 111 | | | test | AA | | true |
I tried union:
(
SELECT *
from table_a
where table_a.date > Date('today')
)
UNION
(
SELECT *
from table_b
where table_b.date > Date('today')
)
But I get a:
ERROR: each UNION query must have the same number of columns
How can this be fixed / is there another way to do this?
Easily :)
(
SELECT id, date, order_id, sku, price, NULL AS description, NULL AS type, NULL AS notes, NULL AS valid
from table_a
where table_a.date > Date('today')
)
UNION
(
SELECT id, date, order_id, NULL AS sku, NULL AS price, description, type, notes, valid
from table_b
where table_b.date > Date('today')
)
Alternatively, instead of UNION you can just JOIN them:
SELECT *
FROM table_a A
JOIN table_b B USING ( id )
WHERE A.date > TIMESTAMP 'TODAY'
AND B.date > TIMESTAMP 'TODAY';
See more options: https://www.postgresql.org/docs/9.5/static/queries-table-expressions.html#QUERIES-JOIN

NULL help in T_SQL script

On SQL Server 2008R2, I am using this script:
SELECT a.id,
a.ea1,
b.ea2
FROM database1table1 AS a
WHERE a.id LIKE N'Active;
The result set looks like this:
+-----+-----+---------------+---------------+
| Row | ID | EA1 | EA2 |
+-----+-----+---------------+---------------+
| 1 | 1 | wf#email.co | NULL |
| 2 | 1 | NULL | wf2#email.co |
| 3 | 1 | NULL | NULL |
| 4 | 2 | NULL | NULL |
| 5 | 3 | wf3#email.co | NULL |
+-----+-----+---------------+---------------+
etc.
ID = business number.
EA = email address.
In the above output, there are three rows where ID=1, but only two of those have email addresses.
I want my result to output the rows where there is no email address. So for this example, the output should only include rows where ID=2.
I have tried adding this WHERE clause:
AND (a.EA1 IS NULL) AND (a.EA2 IS NULL);
It's still returning rows where ID=1, because one of the rows there has no email address.
Can anyone please suggest an amendment to my script which would only return the row where ID=2?
Many thanks
Try with NOT EXISTS
SELECT
*
FROM
Tbl T
WHERE
T.EA1 IS NULL AND
T.EA2 IS NULL AND
NOT EXISTS
(
SELECT 1 FROM Tbl IT
WHERE
IT.ID = T.ID AND
(
IT.EA1 IS NOT NULL OR
IT.EA2 IS NOT NULL
)
)
;WITH CTE
AS
(
SELECT ID,MAX(ROW) AS RW,MAX(EA1) AS EA1,MAX(EA2) AS EA2
FROM #TEMP GROUP BY ID
)
SELECT * FROM CTE WHERE EA1 IS NULL AND EA2 IS NULL
Output:
ID RW EA1 EA2
2 4 NULL NULL

PostgreSQL: Combine Count and DISTINCT ON

Given this table
| id | name | created_at |
| 1 | test | 2015-02-24 11:13:28.605968 |
| 2 | other | 2015-02-24 13:04:56.968004 |
| 3 | test | 2015-02-24 11:14:24.670765 |
| 4 | test | 2015-02-24 11:15:05.293904 |
And this query which returns only the rows id 2 and id 4.
SELECT DISTINCT ON (documents.name) documents.*
FROM "documents"
ORDER BY documents.name, documents.created_at DESC
How can i return the number of rows affected? Something like
SELECT COUNT(DISTINCT ON (documents.name) documents.*) FROM "documents"
You can use an outer query:
SELECT COUNT(1)
FROM (
SELECT DISTINCT ON (name) *
FROM documents
ORDER BY name, created_at DESC
) alias

How to get info about position element in the table?

I have query:
Select * from mytable order by 'date'
And result:
date | item_id | user_id | some_data
------------------------------------------
2015-01-01 | 1 | 1 | null
2015-01-01 | 1 | 1 | null
2015-01-02 | 1 | 1 | null
2015-01-03 | 1 | 1 | null
2015-01-03 | 1 | 2 | null
2015-01-04 | 1 | 1 | null
2015-01-05 | 1 | 2 | null
And I want to get position of first row where user_id = 2. In this example it be 5. How to do it?
select pos_overall
from (
select user_id,
row_number() over (order by "date") as pos_overall,
row_number() over (partition by user_id order by "date") as user_pos
from mytable
) t
where user_id = 2
and user_pos = 1
You can use the row_number() function to number the rows in order of date, user_id and then select the minimum value:
select min(rn)
from (
select
user_id, row_number() over (order by date, user_id) as rn
from mytable
) x
where user_id = 2;
If the item_id can change you might want to include that in the order by clause for the row_number function in the derived table.