Return random value for each row from different table - sql

I'm trying to get random name for each row, but it just shows same random value for every row. What am I missing?
SELECT TOP (1000) v.id,v.[Name], RandomName
FROM [V3_Priva].[dbo].[Vehicle] v
cross join
(Select top 1 ISNULL([Description_cs-CZ], [Description]) RandomName
from crm.Enumeration e
join crm.EnumerationType et on e.EnumerationType_FK = et.Id
where EnumerationType_FK = 12
order by NEWID()) RandomName
Result table

Try using something like the following to drive your lookup.
DECLARE #Rows AS TABLE ( I INT NOT NULL )
DECLARE #Vals AS TABLE ( ID INT IDENTITY, Val NVARCHAR(255) NOT NULL )
INSERT INTO #Rows
VALUES ( 0 )
, ( 1 )
, ( 2 )
, ( 3 )
, ( 4 )
, ( 5 )
, ( 6 )
, ( 7 )
, ( 8 )
, ( 9 )
INSERT INTO #Vals
VALUES ( 'Apple' )
, ( 'Banana' )
, ( 'Peach' )
, ( 'Plum' )
, ( 'Pear' )
WITH cte AS ( SELECT *, ABS(CHECKSUM(NEWID())) % 5 ID FROM #Rows )
SELECT cte.I
, cte.ID
, V.ID
, V.Val
FROM cte
JOIN #Vals V ON V.ID = cte.ID + 1
ORDER BY I
This way new ID is generated for each row, rather than once for the lookup.

Related

T-SQL - Query data based on different filter granularity

-- Data Setup
DECLARE #Table AS TABLE
(
[Id] INT IDENTITY(1, 1)
, [Type] TINYINT
, [TypeOne] INT
, [TypeTwo] INT
, [TypeThree] INT
) ;
INSERT INTO #Table
( [Type]
, [TypeOne]
, [TypeTwo]
, [TypeThree] )
VALUES
( 1, 1, NULL, NULL )
, ( 1, 2, NULL, NULL )
, ( 1, 3, NULL, NULL )
, ( 2, NULL, 10, NULL )
, ( 2, NULL, 20, NULL )
, ( 3, NULL, NULL, 100 )
, ( 3, NULL, NULL, 200 )
, ( 3, NULL, NULL, 300 ) ;
-- Query filters
DECLARE #IncludeTypeOne BIT = 1
, #IncludeTypeTwo BIT = 0 ;
DECLARE #TypeThree_Ids TABLE ( [TypeThree] INT ) ;
INSERT INTO #TypeThree_Ids
VALUES
( 200 )
, ( 300 ) ;
-- Goal: To query #Table based on #IncludeTypeOne, #IncludeTypeTwo, and #TypeThree_Ids values. For first two filters, there's no need to check for specific value of the type in the [TypeOne] and [TypeTwo] columns. However, for the third filter, specific values in the [TypeThree] column must match with the values in #TypeThree_Ids. Is there a way to do this without doing three separate queries and union-ing them all together (the actual table/data is quite large)?
-- Expected output
Id Type TypeOne TypeTwo TypeThree
1 1 1 NULL NULL
2 1 2 NULL NULL
3 1 3 NULL NULL
7 3 NULL NULL 200
8 3 NULL NULL 300
-- My unsuccessful try thus far
SELECT *
FROM #Table
WHERE ( ( #IncludeTypeOne = 0 AND [Type] <> 1 ) OR [Type] = 1 )
AND ( ( #IncludeTypeTwo = 0 AND [Type] <> 2 ) OR [Type] = 2 )
AND ( ( ( SELECT COUNT(1) FROM #TypeThree_Ids ) = 0 AND [Type] <> 3 ) OR [TypeThree] IN ( SELECT [TypeThree] FROM #TypeThree_Ids ) ) ;
-- Actual output
Id Type TypeOne TypeTwo TypeThree
Better to use a join than a sub query -- like this:
SELECT *
FROM #Table
LEFT JOIN #TypeThreeIds ON #Table.TypeThree= #TypeThreeIds.TypeThree
WHERE (#includetypeone = 1 AND [Type] = 1)
OR (#includetypetype = 2 AND [Type] = 2)
OR ([Type] = 3 AND #TypeThreeIds.TypeThree IS NOT NULL)

TSQL - Mapping Parent/Child Hierarchy

Sample Data:
DECLARE #Hierarchy TABLE
(
[ParentId] INT
, [ChildId] INT
) ;
INSERT INTO #Hierarchy
VALUES
( 1, 2 )
, ( 1, 3 )
, ( 2, 4 )
, ( 3, 5 )
, ( 4, 3 )
, ( 4, 6 )
, ( 5, 6 )
, ( 7, 3 ) ;
Current Query:
; WITH CTE AS
(
SELECT [ParentId]
, [ChildId]
, 1 AS [Level]
, CONCAT ( CAST ( [ParentId] AS VARCHAR(MAX) ), '.', CAST ( [ChildId] AS VARCHAR(MAX) ) ) AS [Path]
FROM #Hierarchy
UNION ALL
SELECT [C].[ParentId]
, [T].[ChildId]
, [C].[Level] + 1
, CAST ( [C].[Path] + '.' + CAST([T].[ChildId] AS VARCHAR(MAX) ) AS VARCHAR(MAX) )
FROM CTE AS [C]
JOIN #Hierarchy AS [T]
ON [C].[ChildId] = [T].[ParentId]
)
SELECT *
FROM CTE
ORDER BY [ParentId]
, [Level]
, [ChildId] ;
Goal:
distinctly group levels of shared "path" together
find the shallowest and the deepest levels of the shared "path"
Expected Output:
NOTICE: the records with Orange highlight at the end are manually inserted to show what I'm expecting, but haven't figure out yet.
Group: Basically a "dense rank" of each "groups" of nodes that follow the same path. I think if you look at the values of Group in the above image and relate it to Level and Path field's data, it'll make more sense.
IsShallowest: 1st level (I can see that now that someone brought it up). Just need to figure out how to derive those missing (repeating) records
IsDeepest: max level within the group.
Think IsShallowest and IsDeepest is easy to figure out once "Group" logic is figured out and adding missing (repeated) records.
Please check this solution. It provide the requested solution except adding the extra row which more information is needed
;WITH CTE AS (
SELECT
[ParentId]
, [ChildId]
, 1 AS [Level]
, CONCAT ( CAST ( [ParentId] AS VARCHAR(MAX) ), '.', CAST ( [ChildId] AS VARCHAR(MAX) ) ) AS [Path]
, MyGroup1 = ROW_NUMBER() OVER(ORDER BY [ParentId])
, MyGroup2 = ROW_NUMBER() OVER(ORDER BY [ParentId])
FROM Hierarchy
UNION ALL
SELECT
[C].[ParentId]
, [T].[ChildId]
, [C].[Level] + 1
, CAST ( [C].[Path] + '.' + CAST([T].[ChildId] AS VARCHAR(MAX) ) AS VARCHAR(MAX) )
, MyGroup1 = C.MyGroup1
, MyGroup2 = [C].[MyGroup1] + ROW_NUMBER() OVER(ORDER BY [T].[ParentId]) - 1
FROM CTE AS [C]
JOIN Hierarchy AS [T] ON [C].[ChildId] = [T].[ParentId]
)
, MyCTE2 as (
SELECT
[ParentId]
, [ChildId]
, [Level]
, [Path]
-- un-comment bellow 2 rows to see the logic
--, MyGroup1
--, MyGroup2
, MyGroup = DENSE_RANK() OVER (ORDER BY MyGroup1, MyGroup2)
FROM CTE
),
MyCTE3 as (
SELECT
[ParentId]
, [ChildId]
, [Level]
, [Path]
, MyGroup
, shallowest = ROW_NUMBER() OVER(PARTITION BY MyGroup ORDER BY [Path])
, deepest = ROW_NUMBER() OVER(PARTITION BY MyGroup ORDER BY [Path] DESC)
FROM MyCTE2
)
SELECT
[ParentId]
, [ChildId]
, [Level]
, [Path]
, MyGroup
, ISshallowest = CASE WHEN shallowest = 1 then 1 else 0 END
, Isdeepest = CASE WHEN deepest = 1 then 1 else 0 END
FROM MyCTE3
ORDER BY
--[Path]
[ParentId]
, [Level]
, [ChildId];

SQL - Prepend a value if missing

Code/data:
DECLARE #T TABLE
(
[Col1] VARCHAR(20)
, [RowNum] INT
) ;
INSERT INTO #T
VALUES
( N'second', 1 )
, ( N'fifth', 4 )
, ( N'fourth', 3 )
--, ( N'zzz', 1 )
, ( N'third', 2 )
---- OR when "zzz" is part of this list
--VALUES
-- ( N'second', 2 )
-- , ( N'fifth', 5 )
-- , ( N'fourth', 4 )
-- , ( N'zzz', 1 )
-- , ( N'third', 3 )
SELECT STUFF ((
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'zzz' AS [Col1]
, 1 AS [RowNum]
UNION
SELECT [Col1]
, [RowNum]
FROM #T
) AS [SQ]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
Current output:
fifth,fourth,second,third,zzz
Goal:
Prepend "zzz," in the output string if missing in the 2nd part of the union AND the values should be in ASC ordered based on the values specified in [rownum] field defined in the 2nd part of the union. If "zzz" exists in the 2nd part of the input already (it will always be RowNum 1 in that case), it should return it only once as the first value.
Expected output:
zzz,second,third,fourth,fifth
UPDATED the requirement due to an error on my part when creating this post. Updated code/data represents more accurate scenario. Please note the RowNum seq in the 2nd part of the UNION, it also starts with 1, but this time, it might or might not be associated to "zzz" Basically, I want to prepend "zzz" in the comma-delimited & ordered output if it doesn't exist.
Hope the below one will help you.
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'first' AS [Col1],1 AS [RowNum]
UNION
SELECT [ABC].[Col1],[ABC].[RowNum]
FROM
(
VALUES
( N'second', 2 )
, ( N'fifth', 5 )
, ( N'fourth', 4 )
--, ( N'first', 1 )
, ( N'third', 3 )
) AS [ABC] ( [Col1], [RowNum] )
) AS [SQ]
ORDER BY [RowNum]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
Returns an output
first,second,third,fourth,fifth
Attached the Answer for the updated Scenario-
DECLARE #T TABLE
(
[Col1] VARCHAR(20)
, [RowNum] INT
) ;
INSERT INTO #T
VALUES
( N'second', 1 )
, ( N'fifth', 4 )
, ( N'fourth', 3 )
--, ( N'zzz', 1 )
, ( N'third', 2 )
---- OR when "zzz" is part of this list
--VALUES
-- ( N'second', 2 )
-- , ( N'fifth', 5 )
-- , ( N'fourth', 4 )
-- , ( N'zzz', 1 )
-- , ( N'third', 3 )
SELECT STUFF ((
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'zzz' AS [Col1]
, 0 AS [RowNum]
UNION
SELECT [Col1]
, [RowNum]
FROM #T
) AS [SQ]
ORDER BY [RowNum]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
Returns
zzz,second,third,fourth,fifth
Common Table Expressions (CTEs) provide a handy way of breaking queries down into simpler steps. Note that you can view the results of each step by switching out the last select statement.
with
Assortment as (
-- Start with the "input" rows.
select Col1, RowNum
from ( values ( N'second', 2 ), ( N'fifth', 5 ), ( N'fourth', 4 ),
-- ( N'first', 1 ),
( N'third', 3 ) ) ABC ( Col1, RowNum ) ),
ExtendedAssortment as (
-- Conditionally add "first".
select Col1, RowNum
from Assortment
union all -- Do not remove duplicate rows.
select N'first', 1
where not exists ( select 42 from Assortment where Col1 = N'first' ) )
-- Output the result.
-- Intermediate results may be seen by uncommenting one of the alternate select statements.
-- select * from Assortment;
-- select * from ExtendedAssortment;
select Stuff(
( select N',' + Col1 from ExtendedAssortment order by RowNum for XML path(N''), type).value( N'.[1]', 'NVarChar(max)' ),
1, 1, N'' ) as List;
The same logic can be performed using tables for input:
-- Rows to be included in the comma delimited string.
declare #Input as Table ( Col1 NVarChar(20), RowNum Int );
insert into #Input ( Col1, RowNum ) values
( N'second', 2 ), ( N'fifth', 5 ),
--( N'ZZZ', 17 ), -- Test row.
( N'fourth', 4 ), ( N'third', 3 );
select * from #Input;
-- Mandatory value that must appear in the result. One row only.
declare #Mandatory as Table ( Col1 NVarChar(20), RowNum Int );
-- By using the maximum negative value for an Int this value will be prepended
-- (unless other rows happen to have the same RowNum value).
insert into #Mandatory ( Col1, RowNum ) values ( N'ZZZ', -2147483648 );
select * from #Mandatory;
-- Process the data.
with
AllRows as (
select Col1, RowNum
from #Input
union all
select Col1, RowNum
from #Mandatory
where not exists ( select 42 from #Mandatory as M inner join #Input as I on M.Col1 = I.Col1 ) )
-- Output the result.
-- Intermediate results may be seen by uncommenting the alternate select statement.
--select * from AllRows;
select Stuff(
( select N',' + Col1 from AllRows order by RowNum for XML path(N''), type).value( N'.[1]', 'NVarChar(max)' ),
1, 1, N'' ) as List;

Can correlated subquery following is not null check be replaced with joins?

Can this correlated subquery, where the subquery follows is not null check on the foreign key, be replaced with joins? Example:
select * from TableABC as t
where
(t.label_id is null or t.label_id in ( select t1.id from Labels as t1 where t1.type = '123'))
and
(t.tag_id is null or t.tag_id in ( select t2.id from Tags as t2 where t2.type = '123'))
Described by words: Let's say, I'm looking for all records where if they have label reference defined then the label must be of certain type; same apply for tags.
Or could this query be improved by other means?
It is intended for TSQL (MS SQL).
UPDATE:
I have added table aliases as hinted by HABO. Hope it will improve readability.
I would be inclined to write this as:
select t.*
from TableABC abc
where (abc.label_id is null or
exists (select 1 from labels where l.id = abc.label_id and l.type = 123)
) and
(abc.tag_id is null or
exists (select 1 from tags t where t.id = abc.tag_id and t.type = 123)
);
Then I would be sure I have in index on labels(id, type) and tags(id, type) (if the ids are not already primary keys).
However, your version would probably also have a reasonable execution plan with the right indexes.
I'm not sure that this is an improvement, but it does use left outer join instead of correlated subqueries.
-- Sample data.
declare #TableABC as Table( ABCId Int Identity, LabelId Int, TagId Int );
declare #Labels as Table( LabelId Int Identity, Label VarChar(3) );
declare #Tags as Table( TagId Int Identity, Tag VarChar(3) );
insert into #Labels ( Label ) values ( '123' ), ( '12' ), ( '123' );
insert into #Tags ( Tag ) values ( '123' ), ( '213' ), ( '123' ), ( '312' );
insert into #TableABC ( LabelId, TagId ) values
( 1, 1 ), ( 1, 2 ), ( 1, 3 ), ( 1, 4 ),
( 2, 1 ), ( 2, 2 ), ( 2, 3 ), ( 2, 4 ),
( 3, 1 ), ( 3, 2 ), ( 3, 3 ), ( 3, 4 ),
( NULL, 1 ), ( NULL, 3 ), ( 1, NULL ), ( 3, NULL ), ( NULL, NULL );
select ABC.ABCId, ABC.LabelId, ABC.TagId,
L.LabelId as L_LabelId, L.Label as L_Label,
case when ABC.LabelId is NULL or L.Label = '123' then '<<<' else '' end as 'L_Match',
T.TagId as T_TagId, T.Tag as T_Tag,
case when ABC.TagId is NULL or T.Tag = '123' then '<<<' else '' end as 'T_Match'
from #TableABC as ABC left outer join
#Labels as L on L.LabelId = ABC.LabelId left outer join
#Tags as T on T.TagId = ABC.TagId;
-- "Original" query:
select *
from #TableABC
where ( LabelId is null or LabelId in ( select LabelId from #Labels where Label = '123' ) ) and
( TagId is null or TagId in ( select TagId from #Tags where Tag = '123' ) );
-- Left outer joins:
select ABC.*
from #TableABC as ABC left outer join
#Labels as L on L.LabelId = ABC.LabelId and L.Label = '123' left outer join
#Tags as T on T.TagId = ABC.TagId and T.Tag = '123'
where ( ABC.LabelId is NULL or L.LabelId is not NULL ) and ( ABC.TagId is NULL or T.TagId is not NULL );
Tip: Always use helpful table aliases with joins and apply them to all columns.
With a union
select *
from TableABC
where TableABC.label_id is null
union all
select *
from TableABC
join Labels
on TableABC.label_id = Lables.id
and Lablestype = '123'
on TableABC.label_id = Lables.id or TableABC.label_id is null would return too many rows

SQL How can I order the data using distinct?

I have the following Table 'tbl1'.
declare #tbl1 table ( col1 varchar(32))
insert into #tbl1
values ( 'C1' )
, ( 'B1' )
, ( 'X1' )
, ( 'A1' )
, ( 'B1' )
, ( 'C1' )
, ( 'B1' )
, ( 'A1' )
, ( 'X1' )
, ( 'C1' )
, ( 'D1' )
I tried the following query
select distinct col1
from #tbl1
order by col1
The output should come in the following order, and remove all the duplicate value
C1
B1
X1
A1
D1
You need to specify the order for your items, as others have noted.
Also you need a subquery and grouping to be able to sort over the minimal order column.
declare #source table (id int not null identity primary key, name nvarchar(3));
insert into #source
values ( 'C1' )
, ( 'B1' )
, ( 'X1' )
, ( 'A1' )
, ( 'B1' )
, ( 'C1' )
, ( 'B1' )
, ( 'A1' )
, ( 'X1' )
, ( 'C1' )
, ( 'D1' )
;
with grouped as
(
select min(id) as minId, name from #source
group by name
)
select name from grouped order by minId;
The query could be rewritten without CTE:
select grouped.name from
(select min(id) as minId, name from #source group by name) grouped
order by grouped.minId;
This yields exactly the result you requested.
To repeat what others have pointed out in comments: if you specify no ORDER, then the order of results is not guaranteed. The fact that you get your results in a certain order currently should be treated as coincidental. If you want a certain ordering in your results, you have to be explicit about it!
As an interesting note, in my experience this is especially important if you're doing a DISTINCT in your query, because depending on the statistics for your tables, the engine may or may not decide that ordering the data to execute the DISTINCT is in fact the best possible plan.
Given that you mention a very explicit ordering requirement...
The output should come in the following order, and remove all the duplicate value
C1
B1
X1
A1
D1
...you should make that explicit in your query:
SELECT DISTINCT
*,
CASE
WHEN Col1 = 'C1' THEN 0
WHEN Col1 = 'B1' THEN 1
WHEN Col1 = 'X1' THEN 2
WHEN Col1 = 'A1' THEN 3
WHEN Col1 = 'D1' THEN 4
ELSE 5
END AS SortColumn
FROM tbl1
ORDER BY SortColumn
(extension of Jeroen response)
If your "key" values are dynamic, you normally should have a separate table with the order of the keys...
declare #sort table (id varchar(10), ord int)
insert into #sort
values ( 'C1', 1 )
, ( 'X1', 2 )
, ( 'B1', 3 )
, ( 'A1', 4 )
, ( 'D1', 5 )
then you join/subquery on that table to calculate the SortColumn
-- join
SELECT DISTINCT
t.*,
s.ord SortColumn
FROM #tbl1 t
LEFT JOIN #sort s ON S.id = t.col1
ORDER BY SortColumn
-- subquery
SELECT DISTINCT
t.*,
(SELECT s.ord FROM #sort s WHERE s.id = t.col1) SortColumn
FROM #tbl1 t
ORDER BY SortColumn
declare #tbl1 table ( col1 varchar(32))
insert into #tbl1
values ( 'Basic Salary' )
, ( 'HRA' )
, ( 'OtherAllowance' )
, ( 'PF' )
, ( 'Basic Salary' )
, ( 'HRA' )
, ( 'Other Allowance' )
, ( 'PF' )
, ( 'ESIC' )
, ( 'Basic Salary' )
, ( 'HRA' )
, ( 'Other Allowance' )
, ( 'PF' )
, ( 'Basic Salary' )
select distinct col1
from #tbl1
order by col1