How to divide to multiple column sql? - sql-server

Based on the sql result above i want to divide the result like the image below
I tried using case it return duplicate data.
Anyone have done this or have any idea how to do this?

Can you try this one?
SELECT t1.*,t2.* from yourtable WHERE t1.hatch_num_1 != t2.hatch_num_1
JOIN yourtable t2 ON t1.delay_code_1=t2.delay_code_1
Afterwards you can mention exactly what columns you wan't from both t1 and t2 and mention with 'as' how do you wan't them to be named in your select statement, so instead of having 2 hatch_num_1 you wil have one with _1 and one with _3

;With
a As (SELECT * FROM yourtable X Where X.hatch= 'H1' ),
b AS (SELECT * FROM yourtable Y Where Y.hatch= 'H3')
SELECT A.* ,B.* FROM A , B WHERE A.[delay] = B.[delay]
If you have limited hatches and same time that are repeating then you can do it like this or show me some more records or details then i'll came to know...

Related

MSSQL can't understand what's happening with the action "having count(*) lesser than <some field of other table>"

I've tried to understand some part of an exercise i'm doing and just couldn't get it.
There's a part where 'T' is selected, grouped by 'a' and than it's redirected to "having count(*) < T3.a",
and I don't know how to approach it.
I've tried googling this sort of thing and see if there are similar examples but all other examples were using regular numbers for ex.: "having count(*) < 5" and not whole fields for comparison.
The exercise is this:
MSSQL exercise
create table T(a int, b int);
insert into T values(1,2);
insert into T values(1,1);
insert into T values(2,3);
insert into T values(2,4);
insert into T values(3,4);
insert into T values(4,5);
select T3.b, (select count(T5.a)
from T T5
where T5.a = T3.b)
from (select T1.a as a, T2.b as b
from T T1, T T2
where T1.b < T2.a) as T3
where not exists (select T4.a
from T T4
group by T4.a
having count(*) < T3.a);
I thought that the having count(*) was comparing each value that was grouped by to each value of T3.a in each row and if all rows have met the criteria than the value is getting selected but I somehow get different results.
Can someone please explain to me what is really going on behind this "having count(*) < T3.a" operation?
Thank you in advance.
To repeat myself from the comments, a HAVING is like a WHERE for aggregate functions. You cannot use aggregate function in the WHERE, for example WHERE SUM(SomeColumn) > 5, so you need to do them in the HAVING: HAVING SUM(SomeColumn) > 5. This would returns any rows where the SUM of the column SomeColumn is greater than 5 in the group.
For your expression, HAVING COUNT(*) < T3.a it would only return rows where the value of COUNT(*) is less than the value of T3.a.
Let's break this down to it's separate parts.
First the FROM
from (select T1.a as a, T2.b as b
from T T1, T T2
where T1.b < T2.a) as T3
This uses the old-style deprecated cross-join syntax. It can be rewritten as a normal join:
from (select T1.a as a, T2.b as b
from T T1
join T T2 on T1.b < T2.a
) as T3
If we analyze what it does, we realize that it is actually what is known as a triangular join: every row is self-joined to every row lower than it. This was commonly done when window aggregates were not available.
WHERE
where not exists (select T4.a
from T T4
group by T4.a
having count(*) < T3.a);
This is a correlated subquery: T3.a is a reference to the outer query.
What this predicate says is: for this particular row, there must be no rows in the subquery.
The subquery itself says: take all rows in T, group them by a and count, then only include rows for which the count is less than the outer reference a.
Note that because it is an EXIST, the actual selected value is not used. I suspect this may not have been the intention.
SELECT
select T3.b, (select count(T5.a)
from T T5
where T5.a = T3.b)
We then take b from the first join, and the count from a subquery of all matching T rows. Again, this was common when window aggregates were not available.
So the whole thing can be rewritten as follows:
select T2.b, (select count(T5.a)
from T T5
where T5.a = T3.b)
from (
select *, count(*) over (partition by a) as cnt
from T
) T1
join T T2 on T1.b < T2.a
where T1.cnt < T1.a;
There is something not quite right about the logic in your query, but without knowing what the original intention was, and without seeing the table and column names, I cannot say. The triangular join in particular looks very suspect.

Retrieve all the columns in a table if column for where clause has multiple combinations

I have a table with data that i need to retrieve for each id and its corresponding month
every id has a specific month in which i need to use as a condition to select the records from my table. I would like to know if there is another way of me achieving this instead of having where in () with all the values , my sample is just a small snippet of the actuality data size
Is there any other way I can do this?
please may you reopen the question, i have edited it
You dont have to do one by one. You can use IN operator with the list of ids.
SELECT * FROM YourTable WHERE ID IN (1,2,3....)
If you need to compare more than one column, then define table for combination.
;WITH CTE_IDMonthCombination AS
(
SELECT *
FROM
(
VALUES
(100,1),
(101,2)
.
.
) AS t(ID, Month)
)
SELECT * FROM YourTable AS u
INNER JOIN CTE_IDMonthCombination AS c
ON c.ID = u.ID AND c.Month = u.Month;
GO
Or you can use TempTable, as you have mentioned in the comments.
SELECT *
INTO #t
FROM
(
VALUES
(100,1),
(101,2)
.
.
) AS t(ID, Month);
GO
SELECT * FROM YourTable AS u
INNER JOIN #t AS c
ON c.ID = u.ID AND c.Month = u.Month;
GO

Making equal instance of Union without Union

These days, I've learned about DBMS. And now, I have trouble with using sqlplus.
The problem is I want these two table to be united without 'Union query'.
Table1 = '1','2','3','4','5'
Table2 = '1','2','6','7'
The Union result of these two tables is '1','2','3','4','5','6','7'
But I want to achieve the same result without using Union by only using create, select, or insert.
Please, I really want to know alternative resolution of Union.
technically, you can try
insert
into table1 ( col )
select col
from table2 t2
where not exists (
select 1
from table1 tt1
where tt1.col = t2.col
)
;
but i doubt that this will be much more efficient than a union in the first place.
similar comment holds for a construct like insert into table1 select col from table2 minus select col from table 1.

Converting MS ACCESS query into SQL Server query

I have the following access query which I need to run in mssql:
SELECT
[PUB_op-mstr].[om-job],
Last([PUB_op-mstr].[om-emp]) AS [LastOfom-emp],
Max([PUB_op-mstr].[om-dt-end]) AS [MaxOfom-dt-end],
[PUB_op-mstr].[om-wkctr]
FROM
PUB_wc_mstr INNER JOIN [PUB_op-mstr]
ON
PUB_wc_mstr.wc_wkctr = [PUB_op-mstr].[om-wkctr]
GROUP BY
[PUB_op-mstr].[om-job],
[PUB_op-mstr].[om-wkctr],
PUB_wc_mstr.wc_dept
HAVING
(((Max([PUB_op-mstr].[om-dt-end]))>=Date()-7
And
(Max([PUB_op-mstr].[om-dt-end]))<Date())
AND ((PUB_wc_mstr.wc_dept)="633" Or (PUB_wc_mstr.wc_dept)="646"));
MS SQL doesn't support LAST aggregate function. So, you can just replace it with Min / Max. Or you have write your own SELECT like
[LastOfom-emp] = (SELECT ...
LAST() in Access gives the last element of the column you're looking in.
Example: T1 has one column c1, which contains:
one
two
three
The statement:
SELECT LAST(c1) FROM T1
gives: three
Porting this function to SQL Server is doable, but only if there is (at least) one sorted column in the table. To get the last element of the column, you would have to do:
SELECT TOP(1) c1 FROM T1 ORDER BY c1 DESC;
This would give you the wrong result, namely "two" (because the column isn't sorted). So, to find in this case the right answer, you would need another column, for example an incrementing ID
c1 c2
one 1
two 2
three 3
Now you can:
SELECT TOP(1) c1 FROM T1 ORDER BY c2 DESC;
Since c2 is sorted, you now get the result "three".
Assuming Last([PUB_op-mstr].[om-emp]) is the om-emp value for the maximum om-dt-end, try:
select [om-job], [LastOfom-emp], [MaxOfom-dt-end], [om-wkctr] from
(SELECT [PUB_op-mstr].[om-job],
[PUB_op-mstr].[om-emp] AS [LastOfom-emp],
[PUB_op-mstr].[om-dt-end] AS [MaxOfom-dt-end],
[PUB_op-mstr].[om-wkctr],
row_number() over (partition by [PUB_op-mstr].[om-job],
[PUB_op-mstr].[om-wkctr],
PUB_wc_mstr.wc_dept
order by [PUB_op-mstr].[om-dt-end] desc) rn
FROM PUB_wc_mstr
JOIN [PUB_op-mstr]
ON PUB_wc_mstr.wc_wkctr = [PUB_op-mstr].[om-wkctr]
WHERE PUB_wc_mstr.wc_dept IN ('633','646')
) sq
where rn=1 and
[MaxOfom-dt-end]>=Dateadd(d,-7, getdate()) And
[MaxOfom-dt-end]< getdate()

set difference in SQL query

I'm trying to select records with a statement
SELECT *
FROM A
WHERE
LEFT(B, 5) IN
(SELECT * FROM
(SELECT LEFT(A.B,5), COUNT(DISTINCT A.C) c_count
FROM A
GROUP BY LEFT(B,5)
) p1
WHERE p1.c_count = 1
)
AND C IN
(SELECT * FROM
(SELECT A.C , COUNT(DISTINCT LEFT(A.B,5)) b_count
FROM A
GROUP BY C
) p2
WHERE p2.b_count = 1)
which takes a long time to run ~15 sec.
Is there a better way of writing this SQL?
If you would like to represent Set Difference (A-B) in SQL, here is solution for you.
Let's say you have two tables A and B, and you want to retrieve all records that exist only in A but not in B, where A and B have a relationship via an attribute named ID.
An efficient query for this is:
# (A-B)
SELECT DISTINCT A.* FROM (A LEFT OUTER JOIN B on A.ID=B.ID) WHERE B.ID IS NULL
-from Jayaram Timsina's blog.
You don't need to return data from the nested subqueries. I'm not sure this will make a difference withiut indexing but it's easier to read.
And EXISTS/JOIN is probably nicer IMHO then using IN
SELECT *
FROM
A
JOIN
(SELECT LEFT(B,5) AS b1
FROM A
GROUP BY LEFT(B,5)
HAVING COUNT(DISTINCT C) = 1
) t1 On LEFT(A.B, 5) = t1.b1
JOIN
(SELECT C AS C1
FROM A
GROUP BY C
HAVING COUNT(DISTINCT LEFT(B,5)) = 1
) t2 ON A.C = t2.c1
But you'll need a computed column as marc_s said at least
And 2 indexes: one on (computed, C) and another on (C, computed)
Well, not sure what you're really trying to do here - but obviously, that LEFT(B, 5) expression keeps popping up. Since you're using a function, you're giving up any chance to use an index.
What you could do in your SQL Server table is to create a computed, persisted column for that expression, and then put an index on that:
ALTER TABLE A
ADD LeftB5 AS LEFT(B, 5) PERSISTED
CREATE NONCLUSTERED INDEX IX_LeftB5 ON dbo.A(LeftB5)
Now use the new computed column LeftB5 instead of LEFT(B, 5) anywhere in your query - that should help to speed up certain lookups and GROUP BY operations.
Also - you have a GROUP BY C in there - is that column C indexed?
If you are looking for just set difference between table1 and table2,
the below query is simple that gives the rows that are in table1, but not in table2, such that both tables are instances of the same schema with column names as
columnone, columntwo, ...
with
col1 as (
select columnone from table2
),
col2 as (
select columntwo from table2
)
...
select * from table1
where (
columnone not in col1
and columntwo not in col2
...
);

Resources