sqlconstructor 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.md +16 -0
  3. data/README.md +161 -0
  4. data/Rakefile +11 -0
  5. data/doc/Object.html +267 -0
  6. data/doc/Rakefile.html +150 -0
  7. data/doc/SQLAliasedList.html +717 -0
  8. data/doc/SQLColumn.html +326 -0
  9. data/doc/SQLCondList.html +318 -0
  10. data/doc/SQLConditional.html +1082 -0
  11. data/doc/SQLConditional/BasicCond.html +325 -0
  12. data/doc/SQLConstructor.html +763 -0
  13. data/doc/SQLConstructor/BasicDelete.html +383 -0
  14. data/doc/SQLConstructor/BasicDelete_mysql.html +368 -0
  15. data/doc/SQLConstructor/BasicInsert.html +339 -0
  16. data/doc/SQLConstructor/BasicInsert_mysql.html +325 -0
  17. data/doc/SQLConstructor/BasicJoin.html +408 -0
  18. data/doc/SQLConstructor/BasicJoin_mysql.html +439 -0
  19. data/doc/SQLConstructor/BasicSelect.html +554 -0
  20. data/doc/SQLConstructor/BasicSelect_example.html +288 -0
  21. data/doc/SQLConstructor/BasicSelect_mysql.html +466 -0
  22. data/doc/SQLConstructor/BasicUnion.html +396 -0
  23. data/doc/SQLConstructor/BasicUpdate.html +409 -0
  24. data/doc/SQLConstructor/BasicUpdate_mysql.html +310 -0
  25. data/doc/SQLConstructor/GenericQuery.html +797 -0
  26. data/doc/SQLConstructor/QAttr.html +398 -0
  27. data/doc/SQLConstructorTest.html +603 -0
  28. data/doc/SQLExporter.html +382 -0
  29. data/doc/SQLExporter/Exporter_generic.html +413 -0
  30. data/doc/SQLExporter/Exporter_mysql.html +395 -0
  31. data/doc/SQLObject.html +525 -0
  32. data/doc/SQLValList.html +322 -0
  33. data/doc/SQLValue.html +375 -0
  34. data/doc/created.rid +12 -0
  35. data/doc/images/brick.png +0 -0
  36. data/doc/images/brick_link.png +0 -0
  37. data/doc/images/bug.png +0 -0
  38. data/doc/images/bullet_black.png +0 -0
  39. data/doc/images/bullet_toggle_minus.png +0 -0
  40. data/doc/images/bullet_toggle_plus.png +0 -0
  41. data/doc/images/date.png +0 -0
  42. data/doc/images/find.png +0 -0
  43. data/doc/images/loadingAnimation.gif +0 -0
  44. data/doc/images/macFFBgHack.png +0 -0
  45. data/doc/images/package.png +0 -0
  46. data/doc/images/page_green.png +0 -0
  47. data/doc/images/page_white_text.png +0 -0
  48. data/doc/images/page_white_width.png +0 -0
  49. data/doc/images/plugin.png +0 -0
  50. data/doc/images/ruby.png +0 -0
  51. data/doc/images/tag_green.png +0 -0
  52. data/doc/images/wrench.png +0 -0
  53. data/doc/images/wrench_orange.png +0 -0
  54. data/doc/images/zoom.png +0 -0
  55. data/doc/index.html +356 -0
  56. data/doc/js/darkfish.js +118 -0
  57. data/doc/js/jquery.js +32 -0
  58. data/doc/js/quicksearch.js +114 -0
  59. data/doc/js/thickbox-compressed.js +10 -0
  60. data/doc/lib/dialects/example-constructor_rb.html +52 -0
  61. data/doc/lib/dialects/mysql-constructor_rb.html +52 -0
  62. data/doc/lib/dialects/mysql-exporter_rb.html +54 -0
  63. data/doc/lib/sqlconditional_rb.html +64 -0
  64. data/doc/lib/sqlconstructor_rb.html +52 -0
  65. data/doc/lib/sqlerrors_rb.html +54 -0
  66. data/doc/lib/sqlexporter_rb.html +55 -0
  67. data/doc/lib/sqlobject_rb.html +54 -0
  68. data/doc/rdoc.css +763 -0
  69. data/doc/test/queries_rb.html +56 -0
  70. data/doc/test_rb.html +52 -0
  71. data/lib/dialects/example-constructor.rb +45 -0
  72. data/lib/dialects/mysql-constructor.rb +247 -0
  73. data/lib/dialects/mysql-exporter.rb +108 -0
  74. data/lib/sqlconditional.rb +196 -0
  75. data/lib/sqlconstructor.rb +708 -0
  76. data/lib/sqlerrors.rb +15 -0
  77. data/lib/sqlexporter.rb +125 -0
  78. data/lib/sqlobject.rb +284 -0
  79. data/test/queries.rb +92 -0
  80. metadata +121 -0
@@ -0,0 +1,15 @@
1
+
2
+ ##################################################################################
3
+ # List of error messages
4
+ ##################################################################################
5
+
6
+ ERR_INVALID_COL_NAME = "Invalid column name."
7
+ ERR_INVALID_RULES = "No valid syntax rules found for dialect"
8
+ ERR_NUMERIC_VALUE_EXPECTED = "Numeric argument value expected."
9
+ ERR_UNKNOWN_DIALECT = "Unimplemented SQL dialect specified"
10
+ ERR_UNKNOWN_METHOD = "Unknown method called"
11
+ ERR_UNKNOWN_OPERATOR_TYPE = "Unknown conditional operator type."
12
+ ERR_VALUES_NUM_MISMATCH = "Number of values provided mismatches the number of requested columns."
13
+ ERR_WHERE_INVALID_ARGS = "Hash expected in .where() arguments."
14
+ ERR_WHERE_LIKE_INVALID_ARGS = "Hash with scalar values expected in .where() arguments."
15
+ ERR_NAME_NOT_FOUND = "Could not find named clause by the name"
@@ -0,0 +1,125 @@
1
+
2
+ ##############################################################################################
3
+ # This class implements the interface for exprting SQLConstructor objects to strings.
4
+ ##############################################################################################
5
+ class SQLExporter
6
+
7
+ attr_accessor :dialect, :tidy
8
+ attr_reader :separator
9
+
10
+ # defaults to 'mysql'
11
+ DEFAULT_DIALECT = 'mysql'
12
+
13
+ #############################################################################
14
+ # Class constructor. Called with two optional arguments - dialect and tidy.
15
+ # Dialect determines the translator class (e.g., Exporter_mysql,
16
+ # Exporter_informix etc). Tidy determines whether the output should be
17
+ # formatted and human-readable.
18
+ #############################################################################
19
+ def initialize ( dialect = DEFAULT_DIALECT, tidy = false )
20
+ dialect ||= DEFAULT_DIALECT
21
+ dialect_class = "Exporter_" + dialect.to_s
22
+ begin
23
+ @translator = SQLExporter.const_get( dialect_class ).new( tidy )
24
+ rescue
25
+ raise NameError, ERR_UNKNOWN_DIALECT + ": " + dialect.to_s
26
+ end
27
+ @dialect, @tidy = dialect, tidy
28
+ @separator = @translator.separator
29
+ end
30
+
31
+ #############################################################################
32
+ # The main method to export the obj to string. Calls the @translator's
33
+ # export method.
34
+ #############################################################################
35
+ def export ( obj )
36
+ string = @translator.export obj
37
+ string = @separator + "(" + string + ")" if obj.inline
38
+ return string
39
+ end
40
+
41
+
42
+ #########################################################################################
43
+ # The exporter class of a 'generic' sql dialect. This should be the parent for
44
+ # all dialect-specific exporter classes.
45
+ #########################################################################################
46
+ class Exporter_generic
47
+
48
+ attr_reader :separator
49
+
50
+ #############################################################################
51
+ # Class constructor.
52
+ #############################################################################
53
+ def initialize ( tidy )
54
+ @tidy = tidy
55
+ @separator = @tidy ? "\n" : " "
56
+ end
57
+
58
+ #############################################################################
59
+ # exports a string with a query from object.
60
+ # this method should be called from a child class with defined constant
61
+ # arrays [select|delete|update|insert]_syntax. methods defined in the array
62
+ # are called in the specified order for the object obj.
63
+ #############################################################################
64
+ def export ( obj )
65
+ rules_const_name = obj.class.name.sub( /^.+?::Basic([^_]+).+/, '\1' ).upcase + "_SYNTAX"
66
+ begin
67
+ rules = self.class.const_get( rules_const_name.to_sym )
68
+ rescue NameError
69
+ raise NameError, ERR_INVALID_RULES + " '" + self.send( :dialect ) + "'"
70
+ end
71
+ string = ""
72
+ rules.each do |rule|
73
+ if rule.is_a? String
74
+ string += rule + @separator
75
+ elsif rule.is_a? Symbol
76
+ res = self.send( rule, obj ).to_s
77
+ string += res
78
+ string += @separator if ! res.empty?
79
+ end
80
+ end
81
+ return string
82
+ end
83
+
84
+ #############################################################################
85
+ # Generic representation of the JOIN clause
86
+ #############################################################################
87
+ def gen_joins ( obj )
88
+ arr_joins = [ ]
89
+ if obj.gen_joins
90
+ arr_joins = obj.gen_joins.map { |join| join.to_s }
91
+ end
92
+ return arr_joins.join( @separator )
93
+ end
94
+
95
+ #############################################################################
96
+ # Construct an expression string for an object's attribute defined in
97
+ # in the METHODS constant array.
98
+ #############################################################################
99
+ def method_missing ( method, *args )
100
+ obj = args[0]
101
+ return '' if ! obj.is_a? SQLObject
102
+ result = ""
103
+ _attr = obj.send method
104
+ if _attr.is_a? Array
105
+ result += _attr.join @separator
106
+ elsif _attr
107
+ result += _attr.to_s
108
+ end
109
+
110
+ return result
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ ##################################################################################################
118
+ ##################################################################################################
119
+ # Include dialect-specific classes from ./dialects/exporter/ :
120
+ # This should be done after SQLExporter is defined.
121
+ ##################################################################################################
122
+ ##################################################################################################
123
+
124
+ Dir[ DIALECTS_PATH + "/*-exporter.rb"].each { |file| require file }
125
+
@@ -0,0 +1,284 @@
1
+
2
+ ###############################################################################################
3
+ ### Main class for all objects. All other entities should inherit this class.
4
+ ###############################################################################################
5
+ class SQLObject
6
+
7
+ attr_accessor :alias, :separator, :name, :inline
8
+
9
+ ##########################################################################
10
+ # Do we really need a constructor here?
11
+ ##########################################################################
12
+ def initialize
13
+ @string = nil
14
+ @alias = nil
15
+ @name = nil
16
+ @inline = nil
17
+ end
18
+
19
+ ##########################################################################
20
+ # Set object's name for further named processing
21
+ ##########################################################################
22
+ def _name ( name )
23
+ @name = name.to_s
24
+ return self
25
+ end
26
+
27
+ ##########################################################################
28
+ # Store string representation in @string after the first call
29
+ ##########################################################################
30
+ def to_s
31
+ return @string if @string
32
+ @string = self.to_s
33
+ end
34
+
35
+ ##########################################################################
36
+ # attr_reader for @string, actually an alias to to_s().
37
+ ##########################################################################
38
+ def _string
39
+ to_s
40
+ end
41
+
42
+ ##########################################################################
43
+ # attr_writer for @string
44
+ ##########################################################################
45
+ def _string= ( val )
46
+ @string = val
47
+ end
48
+
49
+ ##########################################################################
50
+ # Convert values to the corresponding internal data types
51
+ ##########################################################################
52
+ def self.get ( *list )
53
+ list.map! do |expr|
54
+ if expr.is_a? SQLObject
55
+ # inline queries go in parens:
56
+ if expr.class == SQLConstructor || expr.is_a?( SQLConstructor::GenericQuery )
57
+ expr.inline = true
58
+ end
59
+ expr
60
+ elsif expr.is_a? Array or expr.is_a? Range
61
+ SQLValList.new *expr.to_a
62
+ elsif expr.is_a? Hash
63
+ SQLAliasedList.new expr
64
+ elsif expr.is_a? Symbol
65
+ SQLColumn.new( expr )
66
+ else
67
+ SQLValue.new( expr )
68
+ end
69
+ end
70
+
71
+ # Return array or scalar, depending on the number of function arguments
72
+ list.length == 1 ? list[0] : list
73
+ end
74
+
75
+ # ##########################################################################
76
+ # # Convert a hash of { obj => alias, ... } to an array of SQLObjects
77
+ # # with defined @alias attribute.
78
+ # ##########################################################################
79
+ # def self.getWithAliases( *list )
80
+ # new_list = [ ]
81
+ # # If list is a hash of objects with aliases:
82
+ # if list.length == 1 && list[0].is_a?( Hash )
83
+ # list.each do |src, _alias|
84
+ # obj = SQLObject.get src
85
+ # obj.alias = _alias
86
+ # new_list << obj
87
+ # end
88
+ # # If list is an array of objects:
89
+ # else
90
+ # new_list = list.map { |src| SQLObject.get src }
91
+ # end
92
+ # return new_list
93
+ # end
94
+
95
+ end
96
+
97
+
98
+ ###############################################################################################
99
+ ### Class representing SQL columns
100
+ ###############################################################################################
101
+ class SQLColumn < SQLObject
102
+
103
+ def initialize ( col = nil )
104
+ @name = col.is_a?( SQLColumn ) ? col.name : col #_prepareName( col )
105
+ end
106
+
107
+ ##########################################################################
108
+ def to_s
109
+ @name.to_s
110
+ end
111
+
112
+ private
113
+
114
+ ##########################################################################
115
+ # Prepare column name (remove all non-alphanumeric/underscore characters)
116
+ ##########################################################################
117
+ def _prepareName ( name )
118
+ name.to_s.gsub /[\W]/, ''
119
+ end
120
+
121
+ end
122
+
123
+
124
+ ###############################################################################################
125
+ ### Class representing SQL scalar values
126
+ ###############################################################################################
127
+ class SQLValue < SQLObject
128
+
129
+ def initialize ( val = nil )
130
+ @value = val.is_a?( SQLValue ) ? val.value : _escape( val )
131
+ end
132
+
133
+ ##########################################################################
134
+ def to_s
135
+ @value
136
+ end
137
+
138
+ private
139
+
140
+ ##########################################################################
141
+ # DERIVED FROM https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
142
+ ##########################################################################
143
+ def _escape ( val )
144
+ case val
145
+ when String then "'#{_quoteString(val.to_s)}'"
146
+ when true then 'TRUE'
147
+ when false then 'FALSE'
148
+ when nil then "NULL"
149
+ when Numeric, Time then val.to_s
150
+ when Symbol then "'#{_quoteString(val.to_s)}'"
151
+ when Class then "'#{val.to_s}'"
152
+ else
153
+ "'#{quoteString( val.to_s )}'"
154
+ end
155
+ end
156
+
157
+ ##########################################################################
158
+ # FROM https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
159
+ # Quotes a string, escaping any ' (single quote) and \ (backslash)
160
+ # characters.
161
+ ##########################################################################
162
+ def _quoteString ( str )
163
+ str.gsub( /\\/, '\&\&' ).gsub( /'/, "''" ) # ' (for ruby-mode)
164
+ end
165
+
166
+ end
167
+
168
+
169
+ ###############################################################################################
170
+ ### Class container - a list of SQLValue scalars
171
+ ###############################################################################################
172
+ class SQLValList < SQLObject
173
+ def initialize ( *list )
174
+ @list = list.map { |item| SQLObject.get item }
175
+ end
176
+
177
+ def << ( list )
178
+ list.map! { |item| SQLObject.get item }
179
+ @list += list
180
+ end
181
+
182
+ def to_s
183
+ return @string if @string
184
+ @string = "(" + @list.join( "," ) + ")"
185
+ end
186
+ end
187
+
188
+
189
+ ###############################################################################################
190
+ ### Class container - a list of SQLObjects with aliases
191
+ ###############################################################################################
192
+ class SQLAliasedList < SQLObject
193
+ attr_writer :no_commas
194
+
195
+ def initialize ( *list )
196
+ @list = _getList *list
197
+ end
198
+
199
+ def << ( *list )
200
+ @list += _getList *list
201
+ return self
202
+ end
203
+
204
+ def push ( *list )
205
+ @list += _getList( *list )
206
+ end
207
+
208
+ def length
209
+ @list.length
210
+ end
211
+
212
+ def each ( &block )
213
+ @list.each &block
214
+ end
215
+
216
+ def delete_if ( &block )
217
+ @list.delete_if &block
218
+ end
219
+
220
+ def [] (i)
221
+ @list[i]
222
+ end
223
+
224
+ def find ( &block )
225
+ @list.find &block
226
+ end
227
+
228
+ def select ( &block )
229
+ @list.each &block
230
+ end
231
+
232
+ def each_with_index ( &block )
233
+ @list.each_with_index &block
234
+ end
235
+
236
+ def to_s
237
+ return @string if @string
238
+ arr = @list.map { |obj| obj.to_s + ( obj.alias ? " " + obj.alias.to_s : "" ) }
239
+ list_separator = @no_commas ? "" : ","
240
+ @string = arr.join list_separator
241
+ end
242
+
243
+ private
244
+
245
+ def _getList ( *list )
246
+ new_list = [ ]
247
+ # If list is a hash of objects with aliases:
248
+ if list.length == 1 && list[0].is_a?( Hash )
249
+ new_list += _hash2array list[0]
250
+ # If list is an array of objects:
251
+ else
252
+ new_list = list.map { |src| SQLObject.get src }
253
+ end
254
+ end
255
+
256
+ def _hash2array ( hash )
257
+ list = [ ]
258
+ hash.each do |item, _alias|
259
+ obj = SQLObject.get item
260
+ obj.alias = _alias
261
+ list << obj
262
+ end
263
+ return list
264
+ end
265
+
266
+ end
267
+
268
+
269
+ ###############################################################################################
270
+ ###
271
+ ###############################################################################################
272
+ class SQLCondList < SQLObject
273
+ def initialize ( hash = { } )
274
+ @hash = Hash[ hash.map{ |k,v| [ SQLObject.get( k ), SQLObject.get( v ) ] } ]
275
+ end
276
+
277
+ def << ( new_hash )
278
+ @hash.merge! new_hash
279
+ end
280
+
281
+ def to_s
282
+ @hash.map{ |k,v| k.to_s + "=" + v.to_s }.join( "," )
283
+ end
284
+ end
@@ -0,0 +1,92 @@
1
+ require 'test/unit'
2
+ require 'sqlconstructor'
3
+
4
+ class SQLConstructorTest < Test::Unit::TestCase
5
+
6
+ def test_select1
7
+ assert_equal "SELECT\n col1,col2\nFROM table1\nJOIN table3 USE INDEX (col1)\nON \n(col1 = ccc1)\nJOIN table4,table5\nON \n(col2 = ccc2 AND col3 = 5)\nWHERE \n(col1 = 123 AND col2 IN ('value1','value2','@\#$%^') AND \n(c1 = 5 AND c2 < 6 OR (c1 = 3 AND c2 IN (1,2,3,4,5) AND s1 = 'somestring')))\nLIMIT 100\nUNION\nSELECT\n baz\nFROM table2\nUNION\nSELECT\n fooz\nFROM table5\nLIMIT 20\n\n",
8
+ select1
9
+ end
10
+
11
+ def test_select2
12
+ assert_equal "SELECT\n t.id,t.tag,c.title category\nFROM tags2Articles t2a\nINNER JOIN tags t\nON \n(t.id = t2a.idTag)\nINNER JOIN categories c\nON \n(t.tagCategory = c.id)\nINNER JOIN \n(SELECT\n a.id\nFROM articles a\nJOIN tags2articles ta\nON \n(a.id = ta.idArticle)\nJOIN tags tsub\nON \n(ta.idTag = tsub.id)\nWHERE \n(tsub.id IN (12,13,16))\nGROUP BY a.id\nHAVING \n(COUNT(DISTINCT tsub.id) = 3)\n) asub\nON \n(t2a.idArticle = asub.id)\n",
13
+ select2
14
+ end
15
+
16
+ def test_insert1
17
+ assert_equal "INSERT\nINTO table2\n SELECT\n name,CONCAT('blah=',ID)\nFROM table1\n\n",
18
+ insert1
19
+ end
20
+
21
+ def test_delete1
22
+ assert_equal "DELETE\nFROM keywords\nWHERE \n(keyword_id IN \n(SELECT\n id\nFROM \n(SELECT\n k.keyword id\nFROM keywords k\nWHERE \n(k.keyword_type = 'CAMPAIGN' AND k.keyword != 'Airtel' AND k.keyword != 'Nokia' AND k.keyword != 'Micromax' AND k.keyword NOT IN \n(SELECT\nDISTINCT\n keyword_id\nFROM customer_analysis\n))\nORDER BY k.keyword_id\n) a\n))\n",
23
+ delete1
24
+ end
25
+
26
+ def test_update1
27
+ assert_equal "UPDATE\n guest g\nSET link_id=\n(SELECT\n MAX(h.host_id)\nFROM guest_data d\nINNER JOIN host_data h\nON \n(d.guest_nm = hhost_nm)\nWHERE \n(d.guest_id = g.guest_id)\nGROUP BY h.venue_nm\nHAVING \n(COUNT(*) = 1)\n)\nWHERE \n(g.guest_id IN \n(SELECT\n d.guest_id\nFROM guest_data d\nINNER JOIN host_data h\nON \n(d.guest_nm = hhost_nm)\nGROUP BY h.venue_nm\nHAVING \n(COUNT(*) = 1)\n))\n",
28
+ update1
29
+ end
30
+
31
+ def select1
32
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
33
+ sql.select(:col1,:col2).from(:table1).where.eq(:col1, 123).and.in(:col2,["value1","value2","@#\$%^"])
34
+ sql.limit( 100 )
35
+ sql.union._name("u1").select(:baz).from(:table2)
36
+ c2 = SQLConditional.new.eq(:c1,3).and.in(:c2,[1,2,3,4,5]).and.eq(:s1,'somestring')
37
+ c1 = SQLConditional.new.eq(:c1,5).and.lt(:c2,6).or.is(c2)
38
+ sql.where.and.is(c1)
39
+ sql.join( :table3 )._name('j1').on.eq( :col1, :ccc1 ).use_index( :col1 )
40
+ sql.join( :table4,:table5 )._name('j2').on.eq( :col2, :ccc2).and.eq( :col3, 5 )
41
+ sql.union._name("u2").select(:fooz).from(:table5).limit( 20 )
42
+ sql.to_s
43
+ end
44
+
45
+ def select2
46
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
47
+ sql.select( :"t.id",:"t.tag",:"c.title" => :category ).from( :tags2Articles => :t2a )
48
+ sql.inner_join( :tags => :t ).on.eq(:"t.id", :"t2a.idTag" )
49
+ sql.inner_join( :categories => :c ).on.eq( :"t.tagCategory", :"c.id" )
50
+ inner_sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
51
+ inner_sql.select( :"a.id" ).from( :articles => :a )
52
+ inner_sql.join( :tags2articles => :ta ).on.eq( :"a.id", :"ta.idArticle" )
53
+ inner_sql.join( :tags => :tsub ).on.eq( :"ta.idTag", :"tsub.id" )
54
+ inner_sql.where.in( :"tsub.id", [12,13,16] ).group_by( :"a.id" ).
55
+ having.eq( :"COUNT(DISTINCT tsub.id)", 3 )
56
+ sql.inner_join( inner_sql => 'asub' ).on.eq( :"t2a.idArticle", :"asub.id" )
57
+ sql.to_s
58
+ end
59
+
60
+ def insert1
61
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
62
+ sql.insert.into(:table2).select(:name, :"CONCAT('blah=',ID)").from(:table1)
63
+ sql.to_s
64
+ end
65
+
66
+ def delete1
67
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
68
+ inner_sel3 = SQLConstructor.new( :tidy => true, :dialect => 'mysql' ).select( :keyword_id ).distinct.from( :customer_analysis )
69
+ inner_sel2 = SQLConstructor.new( :tidy => true, :dialect => 'mysql' ).select( :"k.keyword" => :id ).from( :keywords => :k ).
70
+ where.eq( :"k.keyword_type", "CAMPAIGN" ).and.ne( :"k.keyword", "Airtel" ).
71
+ and.ne( :"k.keyword", "Nokia" ).and.ne( :"k.keyword", "Micromax" ).
72
+ and.not_in( :"k.keyword", inner_sel3 ).order_by( :"k.keyword_id" )
73
+ inner_sel1 = SQLConstructor.new( :tidy => true, :dialect => 'mysql' ).select( :id ).from( inner_sel2 => :a )
74
+ sql.delete.from( :keywords ).where.in( :keyword_id, inner_sel1 )
75
+ sql.to_s
76
+ end
77
+
78
+ def update1
79
+ sql = SQLConstructor.new( :tidy => true, :dialect => 'mysql' )
80
+ in_sel1 = SQLConstructor.new( :tidy => true )
81
+ in_sel1.select( :"MAX(h.host_id)" ).from( :guest_data => :d ).
82
+ inner_join( :host_data => :h ).on.eq( :"d.guest_nm", :hhost_nm ).where.
83
+ eq( :"d.guest_id", :"g.guest_id" ).group_by( :"h.venue_nm" ).having.eq( :"COUNT(*)", 1 )
84
+ in_sel2 = SQLConstructor.new( :dialect => 'mysql', :tidy => true )
85
+ in_sel2.select( :"d.guest_id" ).from( :guest_data => :d ).
86
+ inner_join( :host_data => :h ).on.eq( :"d.guest_nm", :hhost_nm ).
87
+ group_by( :"h.venue_nm" ).having.eq( :"COUNT(*)", 1 )
88
+ sql.update( :guest => :g ).set( :link_id => in_sel1).where.in( :"g.guest_id", in_sel2 )
89
+ sql.to_s
90
+ end
91
+
92
+ end