I have an Entity class as below.
#Entity
#Table(name = "user_MAIN" )
public class userDetails implements Serializable {
#Id
#Column(name = "user_ID")
private int userId;
#OneToMany
#JoinColumn(name = "user_ID", insertable = false, updatable = false)
#Where(clause = "CAST(START_DATE AS DATE) <= CAST(getDate() AS DATE)")
private Set<userContractBasic> userContract=new HashSet<userContractBasic>();
}
I want to join this with userContractBasic entity with a where condition START_DATE > current_date. Here I want only date check required, not date-time check. So I've added CAST in #where clause.
But after adding CAST the query while fetching all results are :
SELECT <fields>
FROM user_main um
LEFT OUTER JOIN user_contract uc ON um.user_id=uc.user_id
AND CAST(uc.START_DATE AS uc.DATE) <= CAST(getDate() AS uc.DATE)
The DATE keyword in ON clause is prepended with the table alias and its breaking the query.
Is there any way I can avoid it?
you need not to specify AS keyword there
just change your #Where with following
#Where(clause = "CAST(START_DATE) <= CAST(getDate())")
Related
After executing a stored procedure, I get the following error:
Msg 512, Level 16, State 1, Procedure sp_ActFTC, Line 64
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I have two tables in the database, FTC_Alt and FichaTecnicaComp, and I need to update the FichaTecnicaComp table on a given date.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_ActFTC]
AS
DECLARE #Codigo NVARCHAR(20),
#DataAlteracao DATE,
#Categoria NVARCHAR(20),
#catord INT,
#SubCategoria NVARCHAR(255),
#subcatord INT,
#Ordem INT,
#CodigoComp NVARCHAR(10),
#DesignacaoComp NVARCHAR(50),
#QuantidadeComp NVARCHAR(25),
#UnidadeComp NVARCHAR(5),
#intRowCount INT,
#upAction NVARCHAR(255);
SELECT #Codigo = ft_alt.codigo
FROM ft_alt;
SELECT #DataAlteracao = ft_alt.dataalteracao
FROM ft_alt;
SELECT Categoria = ftc_alt.categoria
FROM ftc_alt;
SELECT catord = ftc_alt.catord
FROM ftc_alt;
SELECT SubCategoria = ftc_alt.subcategoria
FROM ftc_alt;
SELECT subcatord = ftc_alt.subcatord
FROM ftc_alt;
SELECT Ordem = ftc_alt.ordem
FROM ftc_alt;
SELECT CodigoComp = ftc_alt.codigocomp
FROM ftc_alt;
SELECT DesignacaoComp = ftc_alt.designacaocomp
FROM ftc_alt;
SELECT QuantidadeComp = ftc_alt.quantidadecomp
FROM ftc_alt;
SELECT UnidadeComp = ftc_alt.unidadecomp
FROM ftc_alt;
SELECT #intRowCount = ##RowCount;
SET #upAction = 'Composição nutricional actualizada/alterada'
BEGIN
IF (#DataAlteracao = (SELECT CONVERT(DATE, GETDATE())))
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[FichaTecnicaComp]
SET [Codigo] = #Codigo,
[DataAlteracao] = #DataAlteracao,
categoria = ftc_alt.categoria,
catord = ftc_alt.catord,
subcategoria = ftc_alt.subcategoria,
subcatord = ftc_alt.subcatord,
ordem = ftc_alt.ordem,
codigocomp = ftc_alt.codigocomp,
designacaocomp = ftc_alt.designacaocomp,
quantidadecomp = ftc_alt.quantidadecomp,
unidadecomp = ftc_alt.unidadecomp
FROM [dbo].[FichaTecnicaComp]
JOIN ftc_alt ON [dbo].[FichaTecnicaComp].[Codigo] = (SELECT ft_alt.codigo
FROM ft_alt)
AND [dbo].[FichaTecnicaComp].Ordem = (SELECT FTC_Alt.Ordem
FROM FTC_Alt)
END
END
he expected result is that data in FichaTecnicaComp is updated from FTC_Alt.
Which doesn't happen.
It should be noted that the FichaTecnicaComp has the following working triggers: insertion, update and delete.
If you need the code of those triggers just ask.
Sub queries used in this context can only return a single value, whereas your sub queries are just returning all values of the Ordem and codigo columns. Use the columns directly in the ON clause instead of as sub-selects. You will also want use aliases instead of the full table names. Using only the keyword JOIN will default to an INNER JOIN, which is what I'm assuming you intend to use, however explicitly stating this will help with readability. The first sub query in your post uses ft_alt, instead of ftc_alt, but since this is the only reference to this table I'm guessing this is a typo?
BEGIN
SET NOCOUNT ON
UPDATE FTC
SET
FTC.[Codigo] = FT.Codigo,
FTC.[DataAlteracao] = FT.dataalteracao,
FTC.categoria = ALT.categoria,
FTC.catord = ALT.catord,
FTC.subcategoria = ALT.subcategoria,
FTC.subcatord = ALT.subcatord,
FTC.ordem = ALT.ordem,
FTC.codigocomp = ALT.codigocomp,
FTC.designacaocomp = ALT.designacaocomp,
FTC.quantidadecomp = ALT.quantidadecomp,
FTC.unidadecomp = ALT.unidadecomp
FROM [dbo].[FichaTecnicaComp] FTC
INNER JOIN ft_alt FT ON FTC.Codig = FT.Codigo
INNER JOIN ftc_alt ALT ON FTC.Ordem = ALT.Ordem
END
The error message itself says that one of the sub queries used in this stored procedure returns more than one record, while your update statement can handle only one returned row the way it is written. If you run below queries one by one, you will know where is the problem. Either you need to fix the subquery or may need to use IN instead of = in main query. I hope that helps.
(SELECT ft_alt.codigo
FROM ft_alt)
AND
[dbo].[FichaTecnicaComp].Ordem =
(SELECT FTC_Alt.Ordem
FROM FTC_Alt
And also run below independently.
SELECT FTC_Alt.Ordem
FROM FTC_Alt
I am new to Dapper, so I may be missing something obvious but I don't understand why this query is returning null even though the record exists in the table.
queryResult = db.Query<dynamic>(#"SELECT Id FROM Customer WHERE CustomerId = #CustomerId",
new { CustomerId = theCustomerId }).FirstOrDefault();
I am checking to see if the record exists and in this case it does, yet queryResult is always null. The #CustomerId parameter is a string that I am matching exactly..
If I run the SQL in SQL Server is brings up the record no problem ...
SELECT Id FROM Customer WHERE CustomerId = 'abc123'
where abc123 is the CustomerId
It returns null as you want it to do so
Following is your query getting executed, as part of Query API
"SELECT Id FROM Customer WHERE CustomerId = #CustomerId",
new { CustomerId = theCustomerId }
Now what happens when CustomerId doesn't match, it produces empty IEnumerable<dynamic>, though its a different story why dynamic, you shall use integer assuming Id is an integer
but what FirstOrDefault() does on finding an empty IEnumerable, returns null, so simply remove it do check like Any, dapper by default doesn't return null, your code is forcing it
Best way to check for existence using dapper would be:
string sql = "SELECT count(1) FROM Customer WHERE CustomerId = #CustomerId;";
bool exists = false;
using (var connection = new SqlConnection("connection string"))
{
connection.Open();
exists = connection.ExecuteScalar<bool>(sql, new { CustomerId = "abc123" });
}
As to why your specific example returns null, I suspect it's because you needed brackets around the db.Query like:
queryResult = (db.Query<dynamic>(#"SELECT Id FROM Customer WHERE CustomerId = #CustomerId",
new { CustomerId = theCustomerId })).FirstOrDefault();
Lets say i have two tables with almost the same structure
TableFrom
ID bigint
Username nvarchar
Password nvarchar
Name nvarchar
TableTo
ID bigint
Username nvarchar
Password nvarchar
Now i want to generate an Insert into SQL query ( using parameters ) but only for those fields who are the same in both tables. ( id, username, password )
I thought about reading those two table structure queries into dataTable and after that loop with LINQ to get array of fields which are the same in bot tables ?
Dim dtFrom as new datatable
dim dtTo as NEW dataTable
dtTo = _LoadAvaliableToFields()
dtFrom = _loadAvailableFromFields()
How would that LINQ go ?
After that i need to add the Insert query to database using parameters. Is there any simpler way to do this ?
Using query syntax the "select" query would be very similar to a SQL query:
Dim query =
From idFrom In TableFrom _
Join idTo In TableTo _
On New With {Key .ID = idFrom.ID, Key .U = idFrom.Username, Key .P = idFrom.Password} _
Equals New With {Key .ID = idTo.ID, Key .U = idTo.Username, Key .P = idTo.Password} _
Select idFrom
To do an insert you'd need to add objects to the appropriate collections in the context, then call SaveChanges.
I would note that a direct SQL query would be more efficient:
INSERT INTO {destination}
SELECT f.ID,f.Username,f.Password
FROM TableFrom f
INNER JOIN TableTo t
ON f.ID = t.ID AND f.Username = t.Username AND f.Password = t.Password
Querydsl is generating a stored procedure with a nvarchar parameter for the column, but the table's column type is varchar. This way MS-SQLServer is not able to use its index, which remarkably increases query execution time.
The metadata which is used by Querydsl is generated using Querydsl's MetaDataSerializer (ant target).
How do I force Querydsl to use a varchar stored procedure parameter for the column?
DB table:
TableX with three columns: id (int), ColA (varchar) and ColB (nvarchar)
Generated metadata:
public class QTableX extends com.mysema.query.sql.RelationalPathBase<QTableX> {
private static final long serialVersionUID = 1142355320;
public static final QTableX TableX= new QTableX("TableX");
public final StringPath id = createNumber("id", Integer.class);
public final StringPath colA= createString("ColA");
public final StringPath colB= createString("ColB");
public QTableX(String variable) {
super(QTableX.class, forVariable(variable), "dbo", "TableX");
}
public QTableX(Path<? extends QTableX> path) {
super((Class)path.getType(), path.getMetadata(), "dbo", "TableX");
}
public QTableX(PathMetadata<?> metadata) {
super(QTableX.class, metadata, "dbo", "TableX");
}
}
Querydsl:
SQLQuery query = new SQLQueryImpl(new SQLServerTemplates());
query.from(QTableX.TableX).where(QTableX.TableX.colA.eq("FieldName")
.and(QTableX.TableX.colB.like(".1.")));
generated sql:
declare #p1 int
set #p1=NULL
-- #P0 should be varchar (not nvarchar)
exec dbo.sp_prepare #p1 output,N'#P0 nvarchar(4000),#P1 nvarchar(4000)',N'select TableX.id
from TableX TableX
where TableX.ColA = #P0 and TableX.ColB like #P1 escape ''\''',1
exec dbo.sp_execute #p1, N'FieldName', N'.1.'
In stored procedure MS SQL My query is:
SELECT *
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
I want to give the result table some name.
How can I do this ?
I want to pull it to ADO.Net DataSet.tables["NAME"]
I can imagine a few things you might be meaning.
If you want to persist this result set, for consumption in multiple later queries, you might be looking for SELECT INTO:
SELECT * into NewTableName
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
Where NewTableName is a new name, and a new (permanent) table will be created. If you want that table to go away when you're finished, prefix the name with a #, to make it a temp table.
Alternatively, you might just be wanting to absorb it into a single larger query, in which case you'd be looking at making it a subselect:
SELECT *
FROM (SELECT *
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
) NewTableName
WHERE NewTableName.ColumnValue = 'abc'
or a CTE:
WITH NewTableName AS (
SELECT *
FROM ContentReportRequests a,UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID
)
SELECT * from NewTableName
Finally, you might be talking about pulling the result set into e.g. an ADO.Net DataTable, and you want the name to be set automatically. I'm not sure that that is feasible.
You can use a variable of type table. Read more here: Table Variables In T-SQL
in stored procedure:
select CH.PrimaryKey, CH.Name,
NULL "CustomerHeader"
from CustomerHeader "CH";
--
select CD.PrimaryKey, CD.ShipTo,
NULL "CustomerDetail"
from CustomerDetail "CD";
--
select *, NULL "Orders"
from OrderTable;
in Vb.Net code:
Dim ds As DataSet = Nothing
ds = SqlExecute();
Dim dtCustHeader As DataTable = Nothing
Dim dtCustDetail As DataTable = Nothing
Dim dtOrders As DataTable = Nothing
For Each dt As DataTable In ds.tables
Select Case True
Case dt.Columns.Contains("CustomerHeader")
dtCustHeader = dt
Case dt.Columns.Contains("CustomerDetail")
dtCustDetail = dt
Case dt.Columns.Contains("Orders")
dtOrders = dt
End Select
Next
Kinda SILLY (OR STUPID) that you cannot name tables in a result set.
But this gets you there without a HUGE byte count repeating the table name within each row.
There is still overhead passing the NULL value back for each row. Perhaps passing a BIT value would be smaller yet...
And an alternative is to always use column(0):
in SQL:
select NULL "CustomerDetail", CustName,Addr1,Addr2... from CustomerDetail;
in vb.net:
Dim ds As DataSet = Nothing
ds = SqlExecute();
Dim dtCustHeader As DataTable = Nothing
Dim dtCustDetail As DataTable = Nothing
Dim dtOrders As DataTable = Nothing
For Each dt As DataTable In ds.Tables
Dim tblName As String = dt.Columns(0).ColumnName
Select Case tblName.ToUpper
Case "CUSTOMERDETAIL" : dtCustHeader = dt
Case "CUSTOMERDETAIL" : dtCustDetail = dt
Case "ORDERS" : dtOrders = dt
End Select
Next
These methods get your table-names even if the query returns zero rows.
but the best for last... a way to actually name the tables in the dataset automatically, every time FROM SQL STORED PROCEDURE (with help from your code):
Dim ds As DataSet = Nothing
ds = SqlExecute();
For Each dt As DataTable In ds.Tables
dt.TableName = dt.Columns(0).ColumnName
Next
After this, you may access your tables with the name YOU control within the stored procedure... as it should have been from day-one!
EDIT: selective implementation:
Name the first column in the pattern "TN:Customer".
Your legacy stored procedures work normally, only impacting the stored procedures you wish to modify.
For Each dt As DataTable In mo_LastDataset.Tables
Dim tblName() As String = dt.Columns(0).ColumnName.Split(":")
If tblName.Length >= 2 AndAlso tblName(0).ToUpper = "TN" Then
dt.TableName = tblName(1)
End If
Next
... david ...
SELECT * AS MyTableName
FROM ContentReportRequests a, UserPreferences d
WHERE a.UserID = d.UserID and a.ID =#ID