How to Interchange and update the order of rows in SQL? - sql

I have a table called Device and now i need interchange the order of devid row for devid 5 and devid 6 .
CurrentTable
PID DEVID INID EVTYPEID EVID ALID PARMID TEXTID InputName Input2Name
1 1 0 30 0 100102 0 14 998-TCR1 998-EMG1
1 2 0 30 0 100103 0 15 998-FR 998-TCR2
9 3 0 30 0 100113 0 25 998-TCR2 998-EMG2
0 4 2 30 0 100114 0 26 998-FR NULL
8 5 18 4 53 100114 0 0 998-Sg op 998-Sg cl
4 6 17 4 53 1000114 0 0 SG_PB RA_PB
Expected Result
PID DEVID INID EVTYPEID EVID ALID PARMID TEXTID InputName Input2Name
1 1 0 30 0 100102 0 14 998-TCR1 998-EMG1
1 2 0 30 0 100103 0 15 998-FR 998-TCR2
9 3 0 30 0 100113 0 25 998-TCR2 998-EMG2
0 4 2 30 0 100114 0 26 998-FR NULL
4 6 17 4 53 1000114 0 0 SG_PB RA_PB
8 5 18 4 53 100114 0 0 998-Sg op 998-Sg cl
I do have 150 column in my table and PID and RID are Primary keys

your current select statement plus:
Order by case when DEVID = 6 then 5
when DEVID = 6 then 6
else Devid
end
Not a pretty solution but answers the question.

You need to use a temp number to switch them around.
UPDATE Device SET DEVID=-6 WHERE DEVID=6;
UPDATE Device SET DEVID=6 WHERE DEVID=5;
UPDATE Device SET DEVID=5 WHERE DEVID=-6;
If the other table has a foreign key relationship to the DEVID column then it gets a little trickier. Options:
You can break the foreign key relationship, make the switch, and then
put the key back.
You can create a temp record with DEVID=7 (or
something else not taken) and use 7 as your placeholder in the query
above (instead of -6). Don't forget in that case to delete your
dummy record when you're done.

Related

Pairwise swapping of rows in sql

I have a device settings table with threshold types and values.
Let's say ThresholdType = 0 is Min and ThresholdType = 1 is Max
The initial table looks like this:
DeviceID ThresholdType ThresholdValue
1 0 5
1 1 10
2 0 15
2 1 20
3 0 21
3 1 34
4 0 1
4 1 8
Then I had to change ThresholdType meaning - 0 became Max threshold and 1 became Min one.
I want the table look like that:
DeviceID ThresholdType ThresholdValue
1 0 10
1 1 5
2 0 20
2 1 15
3 0 34
3 1 21
4 0 8
4 1 1
Is it possible to change update it with a single SQL without loops?
Update ThresholdType instead:
update tablename set ThresholdType = 1 - ThresholdType
In case other ThresholdType values might show up later, you can add WHERE ThresholdType IN (1, 2), to be a bit safer.
Just swap the ThresholdType:
UPDATE t SET ThresholdType = CASE ThresholdType
WHEN 1 THEN 0
WHEN 0 THEN 1
ELSE ThresholdType
END
Execute the query exactly once.
You can do:
update t
set ThresholdValue = (
select x.ThresholdValue
from t x
where x.DeviceID = t.DeviceID and x.ThresholdType <> t.ThresholdType
)
Result:
DeviceID ThresholdType ThresholdValue
--------- -------------- --------------
1 0 10
1 1 5
2 0 20
2 1 15
See running example at db<>fiddle.

SQLite computed column in WHERE clause seems to be working(?)

The order in which DMBS execute queries is:
FROM -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT
I was surprised to find out that this query works well on SQLite:
SELECT *, duration / 60 AS length_in_hours
FROM movies
WHERE length_in_hours > 10;
Why is this query working, while in some other cases it seems to fail?
OK, So I run EXPLAIN to see what's going on here.
.eqp full
PRAGMA vdbe_trace=true;
EXPLAIN
SELECT substr(name, 1, 1) AS initial
FROM names
WHERE initial = 'D';
The query results are:
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 11 0 0 Start at 11
1 OpenRead 0 7 0 2 0 root=7 iDb=0; names
2 Rewind 0 10 0 0
3 Column 0 1 2 0 r[2]=names.name
4 Function 6 2 1 substr(3) 0 r[1]=func(r[2..4])
5 Ne 5 9 1 80 if r[1]!=r[5] goto 9
6 Column 0 1 7 0 r[7]=names.name
7 Function 6 7 6 substr(3) 0 r[6]=func(r[7..9])
8 ResultRow 6 1 0 0 output=r[6]
9 Next 0 3 0 1
10 Halt 0 0 0 0
11 Transaction 0 0 10 0 1 usesStmtJournal=0
12 Integer 1 3 0 0 r[3]=1
13 Integer 1 4 0 0 r[4]=1
14 String8 0 5 0 D 0 r[5]='D'
15 Integer 1 8 0 0 r[8]=1
16 Integer 1 9 0 0 r[9]=1
17 Goto 0 1 0 0
In addr 0, the Init opcode sends us to addr 11 which open new Transaction.
Right after that SQLite allocate the integer 1 FOUR TIMES (addr 12-13, 15-16). That's where I started to suspect SQLite may artificially duplicate the expression before the AS into the WHERE clause.
In opcodes 3-5, which happen before the SELECT (opcodes 6-8), we can see that SQLite duplicated our substr into the WHERE clause.

SQL update column depending on other column

sequenceNo IsPoint PointNumber PointSequenceNumber IsCancel
1 1 3168 1 1
2 0 NULL 2 1
3 1 3169 2 1
4 1 2806 3 1
5 1 33322 4 1
6 1 2807 5 1
7 1 2044 6 1
8 1 2046 7 1
9 0 NULL 8 1
10 1 27524 8 1
11 1 670 9 0
12 1 671 10 0
13 1 672 11 0
14 0 NULL 12 1
15 1 1074 12 1
16 1 10844 13 0
17 1 1421 14 0
I need to insert PointNumber to other table depending on value of IsCancel Column if IsCancel is set to 1 I need to insert first iscancel and last IsCancel but sequentially
e.g. STARTPOINT => above sequenceNo 1 for point number 3168 and Iscancel set to 1 I need that point to store in other table StartPoint
ENDPOINT => above sequenceNo 15 for point number 1074 and Iscancel set to 1 I need that point to store in other table as Endpoint
TotalCANCELED => Column hold COUNT IsCancel but only if PointNumber is not NULL
I need to update these columns in other table with following numbers depending on above table
STARTPOINT ENDPOINT TOTALCANCEL
3168 1074 9
Thanks community
I find this logic a bit hard to follow. If I understand this correctly, you can use aggregation -- although you need a little twist to get the end point number:
select max(case when PointSequenceNumber = 1 then pointnumber end) as startpoint,
max(case when PointSequenceNumber = psn then pointnumber end) as endpoint,
sum(case when isCancel = 1 and PointNumber is not null end) as totalCancel
from (select t.*,
max(case when isCancel = 1 and PointNumber is not null then PointSequenceNumber end) over () as max_psn
from t
) t;

How to compare two identical tables for matching or not matching rows?

How to compare two tables for each matching or not matching rows.
I have a table like below where each row is a configuration for a device and i need to compare this with another same table and find which rows are not matching there
PID DEVID INID EVTYPEID EVID ALID PARMID TEXTID
1 20 0 30 0 100102 0 14
1 103 0 30 0 100103 0 15
9 21 0 30 0 100113 0 25
0 31 2 30 0 100114 0 26
8 38 18 4 53 100114 0 0
4 20 17 4 53 1000114 0 0
Thank you
You can use except. You might want to specify the table columns to make sure they are in the correct order.
select *
from tbl1
except
select *
from tbl2
And for matching rows you can use intersect
You can use exists or not exists or in and not in for comparing values between tables.
Select PID, DEVID, INID, EVTYPEID,EVID ALID,PARMID,TEXTID from tableA as A
where exists (select 1 from tableB as B where a.PID=b.PID and a.DEVID=b.DEVID...) - - you can add as per ur requirement)

SQL for MS Access: Another question about COUNT, JOIN, 0s and Dates

I asked a question regarding joins yesterday. However although that answer my initial question, i'm having more problems.
I have a telephony table
ID | Date | Grade
1 07/19/2010 Grade 1
2 07/19/2010 Grade 1
3 07/20/2010 Grade 1
4 07/20/2010 Grade 2
5 07/21/2010 Grade 3
I also have a Grade table
ID | Name
1 Grade 1
2 Grade 2
3 Grade 3
4 Grade 4
5 Grade 5
6 Grade 6
7 Grade 7
8 Grade 8
9 Grade 9
10 Grade 10
11 Grade 11
12 Grade 12
I use the following query to get the COUNT of every grade in the telephony table, it works great.
SELECT grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
GROUP BY grade.ID
ORDER BY 1;
This returns
ID | Total
1 3
2 1
3 1
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
However, what i'm trying to do is the following:
Group by date and only return results between two dates
SELECT telephony.Date, grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
WHERE telephony.Date BETWEEN #07/19/2010# AND #07/23/2010#
GROUP BY telephony.Date, grade.ID
ORDER BY 1;
I'm getting the following
Date | ID | Total
07/19/2010 1 2
07/20/2010 1 1
07/20/2010 2 1
07/21/2010 3 1
It's not returning all the grades with 0 entries between the two dates, only the entries that exist for those dates. What i'm looking for is something like this:
Date | ID | Total
07/19/2010 1 2
07/19/2010 2 0
07/19/2010 3 0
07/19/2010 4 0
07/19/2010 5 0
07/19/2010 6 0
07/19/2010 7 0
07/19/2010 8 0
07/19/2010 9 0
07/19/2010 10 0
07/19/2010 11 0
07/19/2010 12 0
07/20/2010 1 1
07/20/2010 2 1
07/20/2010 3 0
07/20/2010 4 0
07/20/2010 5 0
07/20/2010 6 0
07/20/2010 7 0
07/20/2010 8 0
07/20/2010 9 0
07/20/2010 10 0
07/20/2010 11 0
07/20/2010 12 0
07/21/2010 1 2
07/21/2010 2 0
07/21/2010 3 1
07/21/2010 4 0
07/21/2010 5 0
07/21/2010 6 0
07/21/2010 7 0
07/21/2010 8 0
07/21/2010 9 0
07/21/2010 10 0
07/21/2010 11 0
07/21/2010 12 0
07/22/2010 1 2
07/22/2010 2 0
07/22/2010 3 0
07/22/2010 4 0
07/22/2010 5 0
07/22/2010 6 0
07/22/2010 7 0
07/22/2010 8 0
07/22/2010 9 0
07/22/2010 10 0
07/22/2010 11 0
07/22/2010 12 0
07/23/2010 1 2
07/23/2010 2 0
07/23/2010 3 0
07/23/2010 4 0
07/23/2010 5 0
07/23/2010 6 0
07/23/2010 7 0
07/23/2010 8 0
07/23/2010 9 0
07/23/2010 10 0
07/23/2010 11 0
07/23/2010 12 0
I hope someone can help. I'm using Microsoft Access 2003.
Cheers
Create a separate query on telephony which uses your BETWEEN #07/19/2010# AND #07/23/2010# constraint.
qryTelephonyDateRange:
SELECT *
FROM telephony
WHERE [Date] BETWEEN #07/19/2010# AND #07/23/2010#;
Then, in your original query, use:
LEFT JOIN qryTelephonyDateRange ON grade.ID=qryTelephonyDateRange.Grade
instead of
LEFT JOIN telephony ON grade.ID=telephony.Grade
You could use a subquery instead of a separate named query for qryTelephonyDateRange.
Note Date is a reserved word, so I bracketed the name to avoid ambiguity ... Access' database engine will understand it is supposed to be looking for a field named Date instead of the VBA Date() function. However, if it were my project, I would rename the field to avoid ambiguity ... name it something like tDate.
Update: You asked to see a subquery approach. Try this:
SELECT g.ID, t.[Date], Count(t.Grade) AS Total
FROM
grade AS g
LEFT JOIN (
SELECT Grade, [Date]
FROM telephony
WHERE [Date] BETWEEN #07/19/2010# AND #07/23/2010#
) AS t
ON g.ID=t.Grade
GROUP BY g.ID, t.[Date]
ORDER BY 1, 2;
Try this:
SELECT grade.ID, Count(telephony.Grade) AS Total
FROM grade LEFT JOIN telephony ON grade.ID=telephony.Grade
GROUP BY grade.ID
HAVING COUNT(telephony.Grade) > 0
ORDER BY grade.ID;
That's completely different.
You want a range of individual dates joined with your first table, and the between clause isn't going to do that for you.
I think you'll need a table with all the dates you want, say from 1/1/2010 to 12/31/2010, or whatever range you need to support. One column, 365 or however many rows with one date value each.
then join that table with the ones with the dates and grades, and limit by your date range,
then do the aggregation to count.
Take it one step at a time and it will be easier to figure out.
The way I got it to work was to:
Create a table named Dates with a single primary key date/time field named MyDate (I'm with HansUp on not using reserved words like "Date" for field names).
Fill the table with the date values I wanted (7/19/2010 to 7/23/2010, as in your example).
Write a query with the following SQL statement
SELECT x.MyDate AS [Date], x.ID, Count(t.ID) AS Total
FROM (SELECT Dates.MyDate, Grade.ID FROM Dates, Grade) AS x
LEFT JOIN Telephony AS t ON (x.MyDate = t.Date) AND (x.ID = t.Grade)
GROUP BY x.MyDate, x.ID;
That should get the results you asked for.
The subquery statement in the SQL creates a cross-join to get you every combination of date in the Dates table and grade in the Grade table.
(SELECT Dates.MyDate, Grade.ID FROM Dates, Grade) AS x
Once you have that, then it's just an outer join to the Telephony table to do the rest.